Testing Web API controllers
Integration testing verifies that different parts of an application work correctly together.
Unlike unit tests, integration tests frequently involve application infrastructure concerns. From pinging URLs and passing parameters to returning results (raw content with a given format, like HTML, JSON, and others), you can set up a test host server, which can provide the same level of integration, interact with your code, and allow you to test it just like it was deployed on a real server.
A standard ASP.NET Core server is based on Kestrel, which is a cross-platform web server with the following features:
Fast, lightweight, asynchronous I/O processing
Support for all platforms and versions that .NET Core supports
Easy integration and testing for the code in your API
The good news is that, as part of your integration tests, you don't have to worry about all the features above since they are actually handled by the test host server, assuming you're using it in your test code.
Write integration tests for your project
Integration tests are generally intended to ensure a particular URL in your web server is reachable. Writing integration tests allows for the following:
An HTTP-based call can be established from any supported client (think of using the application as a final user, from a mobile app or web page, for example).
The Web API serving the content can be hit to a specific URL, so the content obtained from the request is effectively HTML as expected.
Content in the response comes as expected (generally in JSON format, but other content types are also supported), with the result of the operation that the client has requested.
Let's pull everything together from the TestContext
component and call our CalculatorController
class, all across the HTTP-based GET method.
using Xunit;
namespace IntegrationTests
{
public class WebCalculatorTests
{
[Fact]
public async void Test_WebCalculatorSum()
{
var context = new TestContext();
using (var client = context.Client)
{
var response = await client.GetAsync("/api/calculator/sum?x=1&y=2");
Assert.True(response.IsSuccessStatusCode);
var content = await response.Content.ReadAsStringAsync();
Assert.Equal("3.0", content);
}
}
}
}
Use Fluent Assertions
Fluent Assertions consist of a set of .NET extension methods that allow you to perform assertions over the outputs of Web API and HTTP-related content and results. They integrate naturally with .NET and can be combined with both TDD and BDD approaches.
In order to have Fluent Assertions in your project, you will need to add it as a NuGet package and include a "using" statement to make the Fluent Assertion classes available in your project.
<PackageReference Include="FluentAssertions.AspNetCore.Mvc" Version="2.1.0" />
The next step is to start using the Fluent Assertion classes, so instead of manually checking things like the response objects from TestContext
and its contents, we can use, for example, .Should().Be()
to perform the assertions.
[Fact]
public async void Test_WebCalculatorSum()
{
var context = new TestContext();
using (var client = context.Client)
{
var response = await client.GetAsync("/api/calculator/sum?x=1&y=2");
response.IsSuccessStatusCode.Should().Be(true);
var content = await response.Content.ReadAsStringAsync();
content.Should().Be("3.0");
}
}
Let's see an example of an unexpected result from the same test:
Code gets readable and descriptive of things that are expected.
Let's recap!
Applying integration tests to web services is an important aspect of testing your components and web server through HTTP content handling, requests, and responses made by the consumers of your Web API. By combining the existing test host with controllers and Fluent Assertions, you can configure a test server, consume its data, and ensure the communication flows as expected by performing assertions in your code, which are a set of extensions for dealing with content responses in a handy way.