JsonClient – easy testing of JSON web services with NUnit

One of the more popular ways of implementing web services is using REST and JSON, because it makes it easy to communicate with the web service from client side (or even server-side) JavaScript. In .NET we can use Windows Communication Foundation (WCF) to fairly easily implement JSON web services.

We might consider using JavaScript to test our JSON web service. But if we don’t have any server-side JavaScript on our project this would require us to run our tests through a browser which makes it less robust for Continuous Integration. Another option is to test our JSON web service from NUnit which have the advantage of reusing the tool set we already use for unit testing the implementation itself.

Testing JSON web services from NUnit requires us to fire up a WebClient instance and sending an HTTP request to the web service and asserting on the HTTP response we get back. However, the interface to the WebClient class is raw strings, so to test a JSON web service would require us to write the input parameters as a JSON string and asserting on the JSON string that is returned. This easily becomes clumsy and unreadable.

It would be much nicer if we could just pass a .NET object and have it converted automatically to a proper JSON string in the HTTP request, and also automatically parse the returned JSON string and pass it as a .NET object for the assertions. Here I will present a simple implementation of a JsonClient class that allows you to write tests like the following:

[Test]
public void GetParticipant()
{
    // when
    var json = jc.Get("participants", new { id = 0 });
 
    // then
    var participant = json.GetParticipantResult;
    Assert.That(participant.Id, Is.EqualTo(0));
    Assert.That(participant.Name, Is.EqualTo("Lars"));
    Assert.That(participant.KeypadId, Is.EqualTo(1234));
}
 
[Test]
public void AddParticipant()
{
    // when
    var json = jc.Post("participants", new { p = new { Name = "Mikkel", KeypadId = 4711 } });
 
    // then
    var participant = json.AddParticipantResult;
    Assert.That(participant.Id, Is.EqualTo(1));
}

Note how we simply construct a .NET object of an anonymous class to pass input parameters in the POST request. Also note how we simply get an object of type dynamic back as the result of the GET request. Also, failed requests gets translated to a JsonException allowing you to easily get at the error properties:

[Test]
public void GetParticipant_Failed()
{
    // when
    var ex = Assert.Throws(() => jc.Get("participants", new { id = 42 }));
 
    // then
    Assert.That(ex.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
    Assert.That(ex.Result.Message, Is.EqualTo("The given key was not present in the dictionary."));
}

The JsonClient class is implemented as a wrapper around the built-in WebClient class handling the translation back and forth between JSON and .NET objects.

Enabling tracing and running the tests shown above against a deployed sample web service implementation gives us the following output showing the actual HTTP requests and responses going over the wire:

POST http://localhost:8113/Wizer/participants
{"p":{"Name":"Mikkel","KeypadId":4711}}
{"AddParticipantResult":{"Id":1,"KeypadId":4711,"Name":"Mikkel"}}

GET http://localhost:8113/Wizer/participants?id=0
{"GetParticipantResult":{"Id":0,"KeypadId":1234,"Name":"Lars"}}

GET http://localhost:8113/Wizer/participants?id=42
Exception: {"Message":"The given key was not present in the dictionary."}

3 passed, 0 failed, 0 skipped, took 1.24 seconds (NUnit 2.6.0).

You can find the source code for the JsonClient class, as well as a sample WCF web service implementation and the corresponding test cases on github or download JsonClient.zip.

This implementation is an adaption of the answer given by Drew Noakes on stackoverflow.

Leave a Reply

  

  

  

* Copy This Password *

* Type Or Paste Password Here *

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>