AspNetCore.Docs/aspnetcore/testing/integration-testing.md

135 lines
9.8 KiB
Markdown
Raw Normal View History

2016-10-29 01:35:15 +08:00
---
title: Integration testing in ASP.NET Core
2016-11-12 00:28:14 +08:00
author: ardalis
description: How to use ASP.NET Core integration testing to ensure that an application's components function correctly.
keywords: ASP.NET Core,integration testing
2016-10-29 01:35:15 +08:00
ms.author: riande
manager: wpickett
2017-02-10 11:19:15 +08:00
ms.date: 02/14/2017
2016-10-29 01:35:15 +08:00
ms.topic: article
ms.assetid: 40d534f2-89b3-4b09-9c2c-3494bf9991c9
2016-11-17 08:24:57 +08:00
ms.technology: aspnet
ms.prod: asp.net-core
2016-10-29 01:35:15 +08:00
uid: testing/integration-testing
---
# Integration testing in ASP.NET Core
2016-10-29 01:35:15 +08:00
By [Steve Smith](https://ardalis.com/)
2016-10-29 01:35:15 +08:00
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.
[View or download sample code](https://github.com/aspnet/Docs/tree/master/aspnetcore/testing/integration-testing/sample)
2016-10-29 01:35:15 +08:00
## Introduction to integration testing
2016-10-29 01:35:15 +08:00
Integration tests verify that different parts of an application work correctly together. Unlike [Unit testing](https://docs.microsoft.com/dotnet/articles/core/testing/unit-testing-with-dotnet-test), 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.
2016-10-29 01:35:15 +08:00
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, especially if you can test the same behavior with a unit test.
> [!NOTE]
> If some behavior can be tested using either a unit test or an integration test, prefer the unit test, since it will be almost always be faster. You might have dozens or hundreds of unit tests with many different inputs but just a handful of integration tests covering the most important scenarios.
2016-10-29 01:35:15 +08:00
Testing the logic within your own methods is usually the domain of unit tests. Testing how your application works within its framework, for example with ASP.NET Core, or with a database is where integration tests come into play. It doesn't take too many integration tests to confirm that you're able to write a row to the database and read it back. You don't need to test every possible permutation of your data access code - you only need to test enough to give you confidence that your application is working properly.
2016-10-29 01:35:15 +08:00
## Integration testing ASP.NET Core
2016-10-29 01:35:15 +08:00
To get set up to run integration tests, you'll need to create a test project, add a reference to your ASP.NET Core web project, and install a test runner. This process is described in the [Unit testing](https://docs.microsoft.com/dotnet/articles/core/testing/unit-testing-with-dotnet-test) documentation, along with more detailed instructions on running tests and recommendations for naming your tests and test classes.
2016-10-29 01:35:15 +08:00
> [!NOTE]
> Separate your unit tests and your integration tests using different projects. This helps ensure you don't accidentally introduce infrastructure concerns into your unit tests and lets you easily choose which set of tests to run.
2016-10-29 01:35:15 +08:00
### The Test Host
2017-02-10 11:19:15 +08:00
ASP.NET Core includes a test host 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. The provided sample includes an integration test project which has been configured to use [xUnit](https://xunit.github.io) and the Test Host. It uses the `Microsoft.AspNetCore.TestHost` NuGet package.
2016-10-29 01:35:15 +08:00
Once the `Microsoft.AspNetCore.TestHost` package is included in the project, you'll be able to create and configure a `TestServer` in your tests. The following test shows how to verify that a request made to the root of a site returns "Hello World!" and should run successfully against the default ASP.NET Core Empty Web template created by Visual Studio.
2016-10-29 01:35:15 +08:00
2016-12-06 04:23:18 +08:00
[!code-csharp[Main](../testing/integration-testing/sample/test/PrimeWeb.IntegrationTests/PrimeWebDefaultRequestShould.cs?name=snippet_WebDefault&highlight=7,16,22)]
2016-10-29 01:35:15 +08:00
This test is using the Arrange-Act-Assert pattern. The Arrange step is done in the constructor, which creates an instance of `TestServer`. A configured `WebHostBuilder` will be used to create a `TestHost`; in this example, the `Configure` method from the system under test (SUT)'s `Startup` class is passed to the `WebHostBuilder`. This method will be used to configure the request pipeline of the `TestServer` identically to how the SUT server would be configured.
2016-10-29 01:35:15 +08:00
In the Act portion of the test, a request is made to the `TestServer` instance for the "/" path, and the response is read back into a string. This string is compared with the expected string of "Hello World!". If they match, the test passes; otherwise, it fails.
2016-10-29 01:35:15 +08:00
Now you can add a few additional integration tests to confirm that the prime checking functionality works via the web application:
2016-10-29 01:35:15 +08:00
2016-12-06 04:23:18 +08:00
[!code-csharp[Main](../testing/integration-testing/sample/test/PrimeWeb.IntegrationTests/PrimeWebCheckPrimeShould.cs?name=snippet_CheckPrime)]
2016-10-29 01:35:15 +08:00
Note that you're not really trying to test the correctness of the prime number checker with these tests but rather that the web application is doing what you expect. You already have unit test coverage that gives you confidence in `PrimeService`, as you can see here:
2016-10-29 01:35:15 +08:00
![Test Explorer](integration-testing/_static/test-explorer.png)
2016-10-29 01:35:15 +08:00
You can learn more about the unit tests in the [Unit testing](https://docs.microsoft.com/dotnet/articles/core/testing/unit-testing-with-dotnet-test) article.
2016-10-29 01:35:15 +08:00
## Refactoring to use middleware
2016-10-29 01:35:15 +08:00
Refactoring is the process of changing an application's code to improve its design without changing its behavior. It should ideally be done when there is a suite of passing tests, since these help ensure the system's behavior remains the same before and after the changes. Looking at the way in which the prime checking logic is implemented in the web application's `Configure` method, you see:
2016-10-29 01:35:15 +08:00
2016-11-18 13:03:07 +08:00
```csharp
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.Run(async (context) =>
{
if (context.Request.Path.Value.Contains("checkprime"))
{
int numberToCheck;
try
{
numberToCheck = int.Parse(context.Request.QueryString.Value.Replace("?", ""));
var primeService = new PrimeService();
if (primeService.IsPrime(numberToCheck))
{
await context.Response.WriteAsync($"{numberToCheck} is prime!");
}
else
{
await context.Response.WriteAsync($"{numberToCheck} is NOT prime!");
}
}
catch
{
await context.Response.WriteAsync("Pass in a number to check in the form /checkprime?5");
}
}
else
{
await context.Response.WriteAsync("Hello World!");
}
});
}
2016-11-18 13:03:07 +08:00
```
2016-10-29 01:35:15 +08:00
This code works, but it's far from how you would like to implement this kind of functionality in an ASP.NET Core application, even as simple as this is. Imagine what the `Configure` method would look like if you needed to add this much code to it every time you add another URL endpoint!
2016-10-29 01:35:15 +08:00
merge aspnetmigration to master (#2668) * Initial aspnet migration * Updating legacy urls * Clearing .gitignore file Clearing .gitignore file because this isnt a normal .net application where we want to strip away debug files, etc. We want to include everything under these folders. * Updating webhooks toc reference * Removing header debug links * Updating webhooks toc * Updating double quotes in metadata to use single quotes * Moving all code blocks to external files * Updating newlines for step-by-step * Fixing indent problem on some code blocks * Fixing newlines in alt attribute for images; Fixing some missing code block references * Resyncing with live content * Refreshing content from production * Trying to get pdf to generate for our aspnetmigration branch * Update .openpublishing.publish.config.json * Refresh from prod; Removing some legacy urls for pages that shouldnt have it * Updating index pages and removing legacy urls * Updating warning and caution notes * Removing downloads * remove aspnet from exclude list (#2549) * First pass at language detection * Updating author and adding in msc.type * Updating code blocks * Updating note styles * Fixing note styles * Updating docfx.json file to allow pdfs and gifs * Fixing note stylings for bold notes * Updating docfx.json to allow exe, zip and wmv files * Fixing note styles with period; Fixing downloads links * Fixing code blocks for razor cs and vb * Fixing more downloads links; Fixing a few code blocks * Removing   html entity * Fixing some more note stylings * Syncing with prod * Fixing issues with content * Rebuilding toc file * Adding back in files accidentally deleted * Fixing some security notes * Fixing some note styles * Updating unknown code blocks * Updating article * Fixing link * Fixing link * Fixing link * Fixing invalid characters * preliminary toc changes * update toc * fix toc folder with only one link * Fixing extra heading * Fixing articles * Reworking ajax pages * Fixing encoding issues * Updating markup in articles * Fixing space * Fixing spacing issues with links * Fixing note styles * Fixing inline note styles * Fixing missing image * Adding space * Rolling back gitignore file and adding a new one for /aspnet * Fixing some code blocks * Updating code block language * Renaming file * Updating code language * Fixing code blocks * Fixing code blocks * Fixing spaces before 'using' * Fixing cs to js * Changing Note type * Updating broken reference * Replacing headings with bolds under notes/tips, etc * Fixing markdown for pipes * Another attempted to fix pipe characters * Fixing markdown for pipes * remove text about being thread-safe (#2630) * Fixing spacing issue with list * Trying to fix pipe issue * new how to choose doc * move choose doc to core folder * add api ref * fix link * Adding in ms.assetid * Removing \ufeff * fix link * link to mvc intro instead of webhooks * add scenarios * put core first, vertical orientation for scenarios * reorganize toc, make overview work like core version * fix yaml * fix broken links * Adding space * add download link * tweak tables * eliminate images * eliminate images 2 * tweak scenario section headings * add link to core in asp.net overview * Removing gears * Updating table * Updating code block languages * fix urls (#2663) * Removing embedded in-article TOC from top of articles * fix urls (#2666) * fix urls * fix urls * Removing embedded in-article TOC from top of articles * Revert "Removing embedded in-article TOC from top of articles" This reverts commit ff1c3ccdf1cf2d705e0bb040144a10fa130796f6. * Revert "Removing embedded in-article TOC from top of articles" This reverts commit 17c37c726d930ec6854b545bab076dffda486ebe.
2017-02-04 05:40:22 +08:00
One option to consider is adding [MVC](xref:mvc/overview) to the application and creating a controller to handle the prime checking. However, assuming you don't currently need any other MVC functionality, that's a bit overkill.
2016-10-29 01:35:15 +08:00
You can, however, take advantage of ASP.NET Core [middleware](xref:fundamentals/middleware), which will help us encapsulate the prime checking logic in its own class and achieve better [separation of concerns](http://deviq.com/separation-of-concerns/) in the `Configure` method.
2016-10-29 01:35:15 +08:00
You want to allow the path the middleware uses to be specified as a parameter, so the middleware class expects a `RequestDelegate` and a `PrimeCheckerOptions` instance in its constructor. If the path of the request doesn't match what this middleware is configured to expect, you simply call the next middleware in the chain and do nothing further. The rest of the implementation code that was in `Configure` is now in the `Invoke` method.
2016-10-29 01:35:15 +08:00
> [!NOTE]
> Since the middleware depends on the `PrimeService` service, you're also requesting an instance of this service with the constructor. The framework will provide this service via [Dependency Injection](xref:fundamentals/dependency-injection), assuming it has been configured, for example in `ConfigureServices`.
2016-10-29 01:35:15 +08:00
[!code-csharp[Main](../testing/integration-testing/sample/src/PrimeWeb/Middleware/PrimeCheckerMiddleware.cs?highlight=39-63)]
2016-10-29 01:35:15 +08:00
Since this middleware acts as an endpoint in the request delegate chain when its path matches, there is no call to `_next.Invoke` when this middleware handles the request.
2016-10-29 01:35:15 +08:00
With this middleware in place and some helpful extension methods created to make configuring it easier, the refactored `Configure` method looks like this:
[!code-csharp[Main](../testing/integration-testing/sample/src/PrimeWeb/Startup.cs?highlight=9&range=19-33)]
Following this refactoring, you're confident that the web application still works as before, since your integration tests are all passing.
> [!NOTE]
> It's a good idea to commit your changes to source control after you complete a refactoring and your tests pass. If you're practicing Test Driven Development, [consider adding Commit to your Red-Green-Refactor cycle](https://ardalis.com/rgrc-is-the-new-red-green-refactor-for-test-first-development).
2016-10-29 01:35:15 +08:00
## Resources
2016-10-29 01:35:15 +08:00
* [Unit testing](https://docs.microsoft.com/dotnet/articles/core/testing/unit-testing-with-dotnet-test)
* [Middleware](xref:fundamentals/middleware)
* [Testing controllers](xref:mvc/controllers/testing)