Although full end-to-end tests allow us to have a great confidence on the software we wrote, component tests offer big advantages and should as well be considered as part of the development process. This article shows how to access Mock-Server from a .NET Core project using a simple Fluent API to facilitate the creation of component tests.

Why component tests?

It’s true that full end-to-end tests, also called broad-stack tests, or simply integration tests, provide us with a great confidence on the quality of software we develop as they excercise all the dependencies our software have in a similar manner it will be done in production. Nevertheless, they also have the following drawbacks:

  • Testing the same functionality more than once, and very often functionality that is out of the scope of the test (e.g. when we test different paths of our component that rely on the same call to an external component)
  • Take longer to run in the continuous delivery pipelines because the behaviour potentially relies on behaviour from an external component that takes time to complete.
  • Harder to develop and maintain as they typically require things like fake data or any kind of pre-existing data setup on the external components storage
  • Often these kind of tests are more subject to environment issues
  • It’s more difficult to test deterministic behaviour

Component tests are, in short, mock-based “integration tests”, but instead of mocking the dependency classes as we do for unit tests, we mock external components entirely (third-party software, other internal services) and test only the business logic of the component that is being subject to test.

As a side-effect, component tests also promote the contract-based (or interface-based) development, which is a good practice anyway.

Of course we can’t have only one of these kinds of tests. We need have both, although it’s healthy to have fewer end-to-end tests when compared to our number component tests.

Mock-Server

Mock-Server is a battle-tested tool that allows us to easily create component tests by mocking the HTTP-based dependencies.

It works simply as any other HTTP-based service in which we can setup our response expectations for a given call.

In fact, one advantages of using Mock-Server is that the same test suite may be run against an instance of Mock-Server, or against the real HTTP-based services, which can be easily done by setting up in advance different configurations for different testing profiles.

Setting up a simple test

Let’s say we have the following design:

Component Tests

The Charging service relies on the Price Calculator service to obtain the rate to be applied to a given voice call.

We want to create a component test for our Charging service to validate that the computed cost is correct, given a price rate and a voice call duration.

First, let’s add the necessary dependencies by running the following terminal commands:

dotnet add package MockServerClientNet
dotnet add package Xunit

The next step is to start an instance of Mock-Server. I’ll be using Docker for convenience, but feel free to use any other method.

docker run -d --name mockserver -p 1080:1080 jamesdbloom/mockserver

The following is an example of how a test could be set up.

// Given: Pricing Calculator returns 1.555 for the given account
MockServerClient msClient = new MockServerClient("127.0.0.1", 1080);
msClient.Reset();

msClient
    .When(Request()
        .WithMethod("GET")
        .WithPath("/prices/rate")
        .WithQueryStringParameters(new Parameter("accountId", "1234")),
        Times.Unlimited())
    .Respond(Response()
        .WithStatusCode(200)
        .WithHeaders(new Header("Content-Type", "application/json"))
        .WithBody("{\"rate\": \"1.155\"}")
    );

// When: Send a charge request for account 1234 and a duration 5 seconds
HttpRequestMessage request = new HttpRequestMessage();
request.Method = HttpMethod.Get;
request.RequestUri = new Uri(
  "http://charging.service/charges?accountId=1234&duration=5");

string responseBody = null;

using (HttpClient client = new HttpClient())
using (HttpResponseMessage res = client.SendAsync(request).Result)
using (HttpContent content = res.Content)
{
    responseBody = content.ReadAsStringAsync().Result;
}

// Then: Verify charged value is correct: 
Assert.Equal(5*1.155, extractChargedValue(responseBody));

This API is very similar to the official Java API (not surprisingly, as C# is also very similar to Java, apart from naming conventions).

Please take a look at here to see more capabilities you can use (e.g. verify requests in the server, setup delays, etc).

Thanks to external contributions to Mock-Server .NET Core client, it’s also possible to load an expectation stored in a file, as in the following example, which allows to easily reuse expectation across multiple tests.

var filePath = Path.Combine("ExpectationFiles", "TestExpectations.json");
mockServerClient.LoadExpectationsFromFile(filePath);

Wrapping-up

In this article we used the MockServerClientNet package that provides a Fluent API to work with Mock-Server. This allow us to easily build component tests by mocking our HTTP-based dependencies.

Hope this is useful. Happy testing.