Testing is an essential part of software development that involves verifying the functionality and performance of an application to ensure it meets the intended purpose. In ASP.NET Core, effective testing can help identify and prevent potential issues before they arise in production environments.
In this article, I’ll guide you through working with WebApplicationFactory
in ASP.NET Core.
The WebApplicationFactory
is a powerful tool that provides a simplified way to set up and execute integration and unit tests for ASP.NET Core applications. By leveraging the WebApplicationFactory, you can better automate your testing process and achieve consistent testing results. Win-win!
Throughout the article, I’ll provide examples of how to use WebApplicationFactory to create coded tests. If you’re ready to improve your testing with ASP.NET Core, let’s jump in!
WebApplicationFactory is a class in the Microsoft.AspNetCore.Mvc.Testing
namespace that provides a way to create a TestServer instance to host an ASP.NET Core application during testing. It is a powerful tool that simplifies and streamlines the testing process for ASP.NET Core developers.
One of the main advantages of using WebApplicationFactory
is that it can help test controllers that interact with the rest of the web application. WebApplicationFactory
creates an in-memory TestServer instance of the web application being tested, providing an environment to test HTTP requests and responses. The in-memory TestServer instance is set up and configured in the same way as a production instance of the web application. This means that WebApplicationFactory
is helpful for integration tests that call multiple APIs and require testing of the interaction of different parts in the web application.
WebApplicationFactory
also has advantages when writing tests isolating parts of your system. It’s possible to test a single function directly without interacting with other parts of the system, such as databases, authentication systems, etc. This makes targeted testing quicker and easier.
WebApplicationFactory
is simple to use and works entirely within C#. Creating a factory is straightforward. A base class is created with configurations, which WebApplicationFactory
is used to build the host from these configurations and finally HttpClient
can be instantiated. The HttpClient
is then used to interact with the in-memory TestServer.
Unit testing is key for software development, particularly in an environment where testing is continuous. These types of tests are lightweight and fast. In ASP.NET Core, unit testing is important to ensure that individual components work as expected. When it comes to ASP.NET Core testing with WebApplicationFactory
, writing unit tests is easy. WebApplicationFactory
provides a standardized way to build integration tests, making it easy to write and maintain tests.
To demonstrate the process of writing unit tests with WebApplicationFactory, let’s take an example of a simple test that checks if a controller action returns the correct response. To do this, a test project should be created and the Microsoft.AspNetCore.Mvc.Testing
package added to the project. The upcoming code examples assume that xUnit is being used as the testing framework.
To test an HTTP endpoint with WebApplicationFactory, a simple test can be written to ensure that the response coming back from our endpoint matches a particular string. Take into account that we should think of issues like the status code, the response’s content, performance, and the feedback to the user if a failure occurs.
We’ll use an HttpClient
to send HTTP requests and read HTTP responses from a specific endpoint. It’s a key part of testing with WebApplicationFactory
since it provides a means to interact with the testing server.
To use HttpClient
with WebApplicationFactory
, the CreateClient()
method must be called from an instance of the factory. This method creates a new client that can be used to send HTTP requests to the in-memory TestServer instance created by WebApplicationFactory
.
An example of using HttpClient
with WebApplicationFactory
is provided below:
public class TestFixture : WebApplicationFactory<Startup>
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.UseEnvironment("Testing");
base.ConfigureWebHost(builder);
}
}
public class SampleControllerTests : IClassFixture<TestFixture>
{
private readonly HttpClient _client;
public SampleControllerTests(TestFixture factory)
{
_client = factory.CreateClient();
}
[Fact]
public async Task SampleController_ReturnsOkResult()
{
// Arrange
var request = new HttpRequestMessage(new HttpMethod("GET"), "/api/sample");
// Act
var response = await _client.SendAsync(request);
// Assert
response.EnsureSuccessStatusCode(); // Status Code 200-299
}
}
In the example above, we use HttpClient
with WebApplicationFactory
to test a specific endpoint. Here, a TestFixture
class inherits from WebApplicationFactory and creates a new instance of Startup
class by specifying it with the type parameter. Then, the CreateClient()
method is called to return an HttpClient
object, which we then use to send an HTTP GET request to a specific endpoint. Finally, we ensure that the status code of the response was a 2xx Success status code.
Integration testing is used to test the interactions between different parts of an application and ensure that they work together as expected. In ASP.NET Core, integration testing is particularly important since the framework provides a wide range of tools and components that need to work together seamlessly. The more moving pieces, the more important different types of coverage are!
For integration tests in ASP.NET Core, the WebApplicationFactory
class creates an in-memory TestServer instance that simulates a production environment and allows you to send requests to the application through the HTTP.Verb methods (i.e GET, POST, DELETE, etc). The tests can be used to evaluate if APIs and database interactions are done correctly, and it allows testing the overall function of the application.
An example of writing an integration test with WebApplicationFactory
would be to test the interaction between multiple APIs and the database. In this example, we test if a register endpoint accepts new users and their credentials are stored correctly in the database.
public class RegisterTests : IClassFixture<WebApplicationFactory<Startup>>
{
private readonly HttpClient _client;
public RegisterTests(WebApplicationFactory<Startup> factory)
{
_client = factory.CreateClient();
}
[Fact]
public async Task Register_ReturnsSuccessResult()
{
// Arrange
var user = new User() { Email = "[email protected]", Password = "testpassword" };
var payload = JsonConvert.SerializeObject(user);
var content = new StringContent(payload, Encoding.UTF8, "application/json");
// Act
var response = await _client.PostAsync("/api/register", content);
// Assert
response.EnsureSuccessStatusCode();
var responseAsString = await response.Content.ReadAsStringAsync();
Assert.Contains("Success", responseAsString);
}
}
In the example above, we create a new WebApplicationFactory
instance of the Startup
class, then call the CreateClient()
method to get an instance of HttpClient
that interacts with the TestServer instance. We test the registration endpoint and verify whether the response returns a success status code.
Here are some best practices for integration testing with WebApplicationFactory
:
Integration testing with WebApplicationFactory
can be a key part of ensuring your ASP.NET Core development goes smoothly. As a C# developer, using WebApplicationFactory
can simplify the process while allowing for increased efficiency and improved code quality.
Mocking dependencies in testing is a technique that isolates the code being tested from external dependencies, such as databases or web APIs. This helps simplify tests and allows developers to test individual components independently. Mocking dependencies is especially important in integration testing, where tests often rely on several different components. Mocking allows developers to isolate the component being tested and verify that it works as intended.
In ASP.NET Core development, WebApplicationFactory
provides a way to mock dependencies in tests. The WebApplicationFactory<TStartup>
class can be overridden to create a new instance of the HttpClient
class that can be used in the tests.
Here’s an example of how to use WebApplicationFactory
to mock a dependency in an ASP.NET Core application:
public class SampleServiceTests : IClassFixture<WebApplicationFactory<Startup>>
{
private readonly HttpClient _client;
public SampleServiceTests(WebApplicationFactory<Startup> factory)
{
_client = factory
.WithWebHostBuilder(builder =>
{
builder.ConfigureTestServices(services =>
{
services.AddTransient<ISampleDependency, MockSampleDependency>();
});
})
.CreateClient();
}
[Fact]
public async Task Sample_Service_Calls_Dependency()
{
// Arrange
var request = new HttpRequestMessage(new HttpMethod("GET"), "/api/sample");
// Act
var response = await _client.SendAsync(request);
// Assert
response.EnsureSuccessStatusCode();
}
}
In the example above, we override an instance of an ISampleDependency
implementation with a mocked version using the ConfigureTestServices
method inside the WebApplicationFactory
class. Then, we create a new instance of HttpClient
that includes the mocked dependency. Finally, it is used to send the HTTP GET request to the required endpoint.
WebApplicationFactory
provides a simple way to mock dependencies in tests using the CreateClient
method. CreateClient
creates a new instance of HttpClient
that can be used to communicate with the in-memory TestServer instance created by WebApplicationFactory
. We can layer in the Moq nuget package to assist us here!
Here’s an example of how to use WebApplicationFactory.CreateClient
to mock a dependency in an ASP.NET Core application:
public class SampleControllerTests : IClassFixture<WebApplicationFactory<Startup>>
{
private readonly HttpClient _client;
public SampleControllerTests(WebApplicationFactory<Startup> factory)
{
_client = factory.CreateClient();
}
[Fact]
public async Task Sample_Controller_Dependency_Mock()
{
// Arrange
var mockDependency = new Mock<IDependency>();
mockDependency.Setup(m => m.GetResult()).Returns("Mocked result");
// Act
var response = await _client.GetAsync("/api/sample");
// Assert
response.EnsureSuccessStatusCode();
var responseContent = await response.Content.ReadAsStringAsync();
Assert.Contains("Mocked result", responseContent);
}
}
In the example above, a new instance of HttpClient
is created using WebApplicationFactory.CreateClient
, and a mocked dependency is injected into the test by overriding the implementation of the IDependency
interface. The test verifies that the endpoint returns the expected response with the overridden implementation.
Testing is an important part of software development (or at least you should make that the case!), especially in ASP.NET Core. Without proper testing, code can be susceptible to bugs, security issues, and unintended consequences. The WebApplicationFactory
in ASP.NET Core is a great tool because of its convenience, flexibility, and ease of use.
Using the WebApplicationFactory
for testing helps you to write effective unit tests and integration tests, including those that test HTTP endpoints. It also allows you to mock dependencies in your applications for more focused testing. I covered how to create a WebApplicationFactory
instance, write unit tests and integration tests using WebApplicationFactory
, and mock dependencies with as well!
Remember to consider best practices and remain pragmatic when testing ASP.NET Core applications with WebApplicationFactory
. Context is key and every situation will be different.
Also published here.