Controllers are a central part of any ASP.NET Core API service and MVC web app. As such, you should have confidence they behave as intended for your app. Automated tests can provide you with this confidence and can detect errors before they reach production.
You need to Test how the controller behaves based on valid or invalid inputs and test controller responses based on the result of the business operation it performs.
However, there are several main differentiated types of tests you should have for your microservices. Unit Tests, Integration Tests, Functional Tests (per microservice) and Service Tests.
Unit Tests - Ensure that individual components/classes of the app work as expected.
Assertions test the component API.
Integration Tests - Ensure that component collaborations work as expected against external
artifacts like databases. Assertions may test component API, UI, or side-effects (such as database I/O, logging, etc.)
Functional Tests (per microservice) - Ensure that the app works as expected from the user’s
perspective, like a use-case.
Service Tests – Ensure that end-to-end service tests, including testing multiple services at the
same time are tested. For this type of testing you need to prepare the environment first which in this case means to spin up the services/containers (like using “docker-compose up” first).
Implementing Unit Tests for ASP.NET Core Web APIs
Unit testing involves testing a part of an app in isolation from its infrastructure and dependencies. When unit testing controller logic, only the contents of a single action is tested, not the behavior of its dependencies or of the framework itself. As you unit test your controller actions, make sure you focus only on its behavior. A controller unit test avoids things like filters, routing, or model binding. By focusing on testing just one thing, unit tests are generally simple to write and quick to run. A well- written set of unit tests can be run frequently without much overhead. However, unit tests do not detect issues in the interaction between components, which is the purpose of integration testing. When writing a unit test of a Web API controller, you directly instance the controller class through the “new” C# language keyword, so it will run as fast as possible, like in the following example.
public class ApiIdeasControllerTests {
[Fact]
public async Task Create_ReturnsBadRequest_GivenInvalidModel() {
// Arrange & Act
var mockRepo = new Mock<IBrainstormSessionRepository>(); var controller = new IdeasController(mockRepo.Object);
107 Architecting and developing Docker applications controller.ModelState.AddModelError("error","some error");
// Act
var result = await controller.Create(model: null); // Assert Assert.IsType<BadRequestObjectResult>(result); } }
---
--- TBD SECTION IN DRAFT ---
--- Further implementation details for Unit Tests ---
---
Implementing Integration and Functional Tests per isolated microservice
As introduced, Integration Tests and Functional Tests have different goals and purposes. However, the way you implement both when testing ASP.NET Core controllers is pretty similar, so below it is only explained how to implement an Integration Tests.
Integration testing ensures that an application's components function correctly when assembled together. ASP.NET Core supports integration testing using unit test frameworks and a built-in test web host that can be used to handle requests without network overhead.
Unlike Unit testing, integration tests frequently involve application infrastructure concerns, such as a database, file system, network resources, or web requests and responses. Unit tests use fakes or mock objects in place of these concerns, but the purpose of integration tests is to confirm that the system works as expected with these systems, so in this case you won’t use fakes or mock objects but including the infrastructure, like database access or services invocation from the outside. Integration tests, because they exercise larger segments of code and because they rely on
infrastructure elements, tend to be orders of magnitude slower than unit tests. Thus, it's a good idea to limit how many integration tests you write.
ASP.NET Core includes a test host available in a NuGet component as Microsoft.AspNetCore.TestHost that can be added to integration test projects and used to host ASP.NET Core applications, serving test requests without the need for a real web host.
AS you can see in the following code, when creating integration tests of ASP.NET Core controllers, you would instanciate the controllers through the Test Host so it is comparable to an HTTP request but running faster.
public class PrimeWebDefaultRequestShould {
private readonly TestServer _server; private readonly HttpClient _client; public PrimeWebDefaultRequestShould() {
// Arrange
_server = new TestServer(new WebHostBuilder()
.UseStartup<Startup>()); _client = _server.CreateClient();
108 Architecting and developing Docker applications
} [Fact]
public async Task ReturnHelloWorld() {
// Act
var response = await _client.GetAsync("/"); response.EnsureSuccessStatusCode();
var responseString = await response.Content.ReadAsStringAsync(); // Assert Assert.Equal("Hello World!", responseString); } }
---
--- TBD SECTION IN DRAFT ---
--- Further implementation details for Integration and Functional Tests ---
---
For additional details on how to create unit tests and integration tests for ASP.NET Core Web API and MVC applications, read the following references.References – Testing ASP.NET Core Web APIs and MVC Apps
Testing Controllers in ASP.NET Core:
https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/testing Integration Tests in ASP.NET Core
https://docs.microsoft.com/en-us/aspnet/core/testing/integration-testing Unit Testing in .NET Core using dotnet test
https://docs.microsoft.com/en-us/dotnet/articles/core/testing/unit-testing-with-dotnet-test