Testing .NET Aspire projects
In this article, you'll learn how to create a test project, write, and run tests for your .NET Aspire projects. The tests in this article are not unit tests, but rather functional or integration tests. .NET Aspire include an testing project templates that you can use to test your .NET Aspire projects. The testing project templates are available for MSTest, NUnit, and xUnit testing frameworks and includes a sample test that you can use as a starting point for your tests.
Create a test project
The easiest way to create a .NET Aspire test project is to use the testing project template. If you're starting a new .NET Aspire project and want to include test projects, the Visual Studio tooling supports that option. If you're adding a test project to an existing .NET Aspire project, you can use the dotnet new
command to create a test project:
dotnet new aspire-xunit
dotnet new aspire-mstest
dotnet new aspire-nunit
Explore the test project
The following example test project was created as part of the .NET Aspire Starter Application template. If you're unfamiliar with it, see Quickstart: Build your first .NET Aspire project. The .NET Aspire test project takes a project reference dependency on the target app host. Consider the template project:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting.Testing" Version="8.2.0" />
<PackageReference Include="coverlet.collector" Version="6.0.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.0" />
<PackageReference Include="xunit" Version="2.9.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AspireApp.AppHost\AspireApp.AppHost.csproj" />
</ItemGroup>
<ItemGroup>
<Using Include="System.Net" />
<Using Include="Microsoft.Extensions.DependencyInjection" />
<Using Include="Aspire.Hosting.ApplicationModel" />
<Using Include="Aspire.Hosting.Testing" />
<Using Include="Xunit" />
</ItemGroup>
</Project>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<PropertyGroup>
<EnableMSTestRunner>true</EnableMSTestRunner>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting.Testing" Version="8.2.0" />
<PackageReference Include="MSTest" Version="3.5.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AspireApp.AppHost\AspireApp.AppHost.csproj" />
</ItemGroup>
<ItemGroup>
<Using Include="System.Net" />
<Using Include="Microsoft.Extensions.DependencyInjection" />
<Using Include="Aspire.Hosting.ApplicationModel" />
<Using Include="Aspire.Hosting.Testing" />
<Using Include="Microsoft.VisualStudio.TestTools.UnitTesting" />
</ItemGroup>
</Project>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting.Testing" Version="8.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.0" />
<PackageReference Include="NUnit" Version="4.2.2" />
<PackageReference Include="NUnit.Analyzers" Version="4.3.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AspireApp.AppHost\AspireApp.AppHost.csproj" />
</ItemGroup>
<ItemGroup>
<Using Include="System.Net" />
<Using Include="Microsoft.Extensions.DependencyInjection" />
<Using Include="Aspire.Hosting.ApplicationModel" />
<Using Include="Aspire.Hosting.Testing" />
<Using Include="NUnit.Framework" />
</ItemGroup>
</Project>
The preceding project file is fairly standard. There's a PackageReference
to the Aspire.Hosting.Testing NuGet package, which includes the required types to write tests for .NET Aspire projects.
The template test project includes a WebTests
class with a single test. The test verifies the following scenario:
- The app host is successfully created and started.
- The
webfrontend
resource is available and running. - An HTTP request can be made to the
webfrontend
resource and returns a successful response (HTTP 200 OK).
Consider the following test class:
namespace AspireApp.Tests;
public class WebTests
{
[Fact]
public async Task GetWebResourceRootReturnsOkStatusCode()
{
// Arrange
var appHost = await DistributedApplicationTestingBuilder
.CreateAsync<Projects.AspireApp_AppHost>();
appHost.Services.ConfigureHttpClientDefaults(clientBuilder =>
{
clientBuilder.AddStandardResilienceHandler();
});
await using var app = await appHost.BuildAsync();
var resourceNotificationService = app.Services
.GetRequiredService<ResourceNotificationService>();
await app.StartAsync();
// Act
var httpClient = app.CreateHttpClient("webfrontend");
await resourceNotificationService.WaitForResourceAsync(
"webfrontend",
KnownResourceStates.Running
)
.WaitAsync(TimeSpan.FromSeconds(30));
var response = await httpClient.GetAsync("/");
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
}
namespace AspireApp.Tests;
[TestClass]
public class WebTests
{
[TestMethod]
public async Task GetWebResourceRootReturnsOkStatusCode()
{
// Arrange
var appHost = await DistributedApplicationTestingBuilder
.CreateAsync<Projects.AspireApp_AppHost>();
appHost.Services.ConfigureHttpClientDefaults(clientBuilder =>
{
clientBuilder.AddStandardResilienceHandler();
});
await using var app = await appHost.BuildAsync();
var resourceNotificationService = app.Services
.GetRequiredService<ResourceNotificationService>();
await app.StartAsync();
// Act
var httpClient = app.CreateHttpClient("webfrontend");
await resourceNotificationService.WaitForResourceAsync(
"webfrontend",
KnownResourceStates.Running
)
.WaitAsync(TimeSpan.FromSeconds(30));
var response = await httpClient.GetAsync("/");
// Assert
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}
}
namespace AspireApp.Tests;
public class WebTests
{
[Test]
public async Task GetWebResourceRootReturnsOkStatusCode()
{
// Arrange
var appHost = await DistributedApplicationTestingBuilder
.CreateAsync<Projects.AspireApp_AppHost>();
appHost.Services.ConfigureHttpClientDefaults(clientBuilder =>
{
clientBuilder.AddStandardResilienceHandler();
});
await using var app = await appHost.BuildAsync();
var resourceNotificationService = app.Services
.GetRequiredService<ResourceNotificationService>();
await app.StartAsync();
// Act
var httpClient = app.CreateHttpClient("webfrontend");
await resourceNotificationService.WaitForResourceAsync(
"webfrontend",
KnownResourceStates.Running
)
.WaitAsync(TimeSpan.FromSeconds(30));
var response = await httpClient.GetAsync("/");
// Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
}
}
The preceding code:
- Relies on the
DistributedApplicationTestingBuilder
to asynchronously create the app host.- The
appHost
is an instance ofIDistributedApplicationTestingBuilder
that represents the app host. - The
appHost
instance has its service collection configured with the standard HTTP resilience handler. For more information, see Build resilient HTTP apps: Key development patterns.
- The
- The
appHost
has itsBuildAsync
method invoked, which returns theDistributedApplication
instance as theapp
.- The
app
has its service provider get the ResourceNotificationService instance. - The
app
is started asynchronously.
- The
- An
HttpClient
is created for thewebfrontend
resource by callingapp.CreateHttpClient
. - The
resourceNotificationService
is used to wait for thewebfrontend
resource to be available and running. - A simple HTTP GET request is made to the root of the
webfrontend
resource. - The test asserts that the response status code is
OK
.
Summary
By using the .NET Aspire testing project template, you can easily create test projects for your .NET Aspire projects. The template project includes a sample test that you can use as a starting point for your tests. The DistributedApplicationTestingBuilder
follows a familiar pattern to the WebApplicationFactory
in ASP.NET Core. It allows you to create a test host for your distributed application and run tests against it.