Escribe tu primera prueba de .NET.NET Aspire
En este artículo, aprenderá a crear un proyecto de prueba, escribir pruebas y ejecutarlas para sus soluciones de .NET.NET Aspire. Las pruebas de este artículo no son pruebas unitarias, sino pruebas funcionales o de integración. .NET .NET Aspire incluye varias variaciones de plantillas de proyecto de prueba que puede usar para probar las dependencias de recursos de .NET.NET Aspire y sus comunicaciones. Las plantillas de proyecto de prueba están disponibles para marcos de pruebas msTest, NUnit y xUnit e incluyen una prueba de ejemplo que puede usar como punto de partida para las pruebas.
Las plantillas de proyecto de prueba del
Creación de un proyecto de prueba
La manera más fácil de crear un proyecto de prueba de .NET.NET Aspire consiste en usar la plantilla de proyecto de prueba. Si va a iniciar un nuevo proyecto de .NET.NET Aspire y desea incluir proyectos de prueba, las herramientas de Visual Studio admiten esa opción. Si va a agregar un proyecto de prueba a un proyecto de .NET.NET Aspire existente, puede usar el comando dotnet new
para crear un proyecto de prueba:
dotnet new aspire-xunit
dotnet new aspire-mstest
dotnet new aspire-nunit
Para obtener más información, consulte la documentación del comando dotnet new de la CLI .NET.
Exploración del proyecto de prueba
El siguiente proyecto de prueba de ejemplo se creó como parte de la plantilla Aplicación Starter .NET.NET Aspire. Si no está familiarizado con él, consulte Guía rápida: Cree su primer proyecto de .NET.NET Aspire. El proyecto de prueba de .NET.NET Aspire adquiere una dependencia de referencia de proyecto en el host de la aplicación de destino. Considere el proyecto de plantilla:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting.Testing" Version="9.0.0" />
<PackageReference Include="coverlet.collector" Version="6.0.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.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="Xunit" />
</ItemGroup>
</Project>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.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="9.0.0" />
<PackageReference Include="MSTest" Version="3.7.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="Microsoft.VisualStudio.TestTools.UnitTesting" />
</ItemGroup>
</Project>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting.Testing" Version="9.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="NUnit" Version="4.3.1" />
<PackageReference Include="NUnit.Analyzers" Version="4.5.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>
El archivo de proyecto anterior es bastante estándar. Hay un PackageReference
para el 📦Aspire.Hosting.Testing paquete NuGet, que incluye los tipos necesarios para escribir pruebas para proyectos de .NET.NET Aspire.
El proyecto de prueba de plantilla incluye una clase IntegrationTest1
con una sola prueba. La prueba comprueba el siguiente escenario:
- El host de la aplicación se ha creado e iniciado correctamente.
- El recurso
webfrontend
está disponible y en ejecución. - Se puede realizar una solicitud HTTP al recurso de
webfrontend
y devuelve una respuesta correcta (HTTP 200 OK).
Tenga en cuenta la siguiente clase de prueba:
namespace AspireApp.Tests;
public class IntegrationTest1
{
[Fact]
public async Task GetWebResourceRootReturnsOkStatusCode()
{
// Arrange
var appHost = await DistributedApplicationTestingBuilder
.CreateAsync<Projects.AspireApp_AppHost>();
appHost.Services.ConfigureHttpClientDefaults(clientBuilder =>
{
clientBuilder.AddStandardResilienceHandler();
});
// To output logs to the xUnit.net ITestOutputHelper,
// consider adding a package from https://www.nuget.org/packages?q=xunit+logging
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 IntegrationTest1
{
[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 IntegrationTest1
{
[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));
}
}
El código anterior:
- Se basa en la API de DistributedApplicationTestingBuilder.CreateAsync para crear de forma asincrónica el host de la aplicación.
- El
appHost
es una instancia deIDistributedApplicationTestingBuilder
que representa el host de la aplicación. - La instancia de
appHost
tiene configurada su colección de servicios con el controlador de resistencia HTTP estándar. Para obtener más información, consulte Creación de aplicaciones HTTP resilientes: Patrones clave de desarrollo.
- El
- El
appHost
tiene su método IDistributedApplicationTestingBuilder.BuildAsync(CancellationToken) invocado, que devuelve la instancia deDistributedApplication
comoapp
.- El proveedor de servicios de
app
obtiene la instancia de ResourceNotificationService. - El
app
se inicia de forma asincrónica.
- El proveedor de servicios de
- Se crea un HttpClient para el recurso de
webfrontend
llamando aapp.CreateHttpClient
. - El
resourceNotificationService
se usa para esperar a que el recurso dewebfrontend
esté disponible y en ejecución. - Se realiza una solicitud HTTP GET simple a la raíz del recurso
webfrontend
. - La prueba afirma que el código de estado de respuesta es
OK
.
Probar variables de entorno de recursos
Para probar de manera más detallada los recursos y sus dependencias expresadas en la solución de .NET.NET Aspire, puede afirmar que las variables de entorno están correctamente inyectadas. En el ejemplo siguiente se muestra cómo probar que el recurso de webfrontend
tiene una variable de entorno HTTPS que se resuelve en el recurso de apiservice
:
using Aspire.Hosting;
namespace AspireApp.Tests;
public class EnvVarTests
{
[Fact]
public async Task WebResourceEnvVarsResolveToApiService()
{
// Arrange
var appHost = await DistributedApplicationTestingBuilder
.CreateAsync<Projects.AspireApp_AppHost>();
var frontend = (IResourceWithEnvironment)appHost.Resources
.Single(static r => r.Name == "webfrontend");
// Act
var envVars = await frontend.GetEnvironmentVariableValuesAsync(
DistributedApplicationOperation.Publish);
// Assert
Assert.Contains(envVars, static (kvp) =>
{
var (key, value) = kvp;
return key is "services__apiservice__https__0"
&& value is "{apiservice.bindings.https.url}";
});
}
}
using Aspire.Hosting;
namespace AspireApp.Tests;
[TestClass]
public class EnvVarTests
{
[TestMethod]
public async Task WebResourceEnvVarsResolveToApiService()
{
// Arrange
var appHost = await DistributedApplicationTestingBuilder
.CreateAsync<Projects.AspireApp_AppHost>();
var frontend = (IResourceWithEnvironment)appHost.Resources
.Single(static r => r.Name == "webfrontend");
// Act
var envVars = await frontend.GetEnvironmentVariableValuesAsync(
DistributedApplicationOperation.Publish);
// Assert
CollectionAssert.Contains(envVars,
new KeyValuePair<string, string>(
key: "services__apiservice__https__0",
value: "{apiservice.bindings.https.url}"));
}
}
using Aspire.Hosting;
namespace AspireApp.Tests;
public class EnvVarTests
{
[Test]
public async Task WebResourceEnvVarsResolveToApiService()
{
// Arrange
var appHost = await DistributedApplicationTestingBuilder
.CreateAsync<Projects.AspireApp_AppHost>();
var frontend = (IResourceWithEnvironment)appHost.Resources
.Single(static r => r.Name == "webfrontend");
// Act
var envVars = await frontend.GetEnvironmentVariableValuesAsync(
DistributedApplicationOperation.Publish);
// Assert
Assert.That(envVars, Does.Contain(
new KeyValuePair<string, string>(
key: "services__apiservice__https__0",
value: "{apiservice.bindings.https.url}")));
}
}
El código anterior:
- Se basa en la API de DistributedApplicationTestingBuilder.CreateAsync para crear de forma asincrónica el host de la aplicación.
- La instancia de
builder
se usa para recuperar una instancia de IResourceWithEnvironment llamada "webfrontend" de la IDistributedApplicationTestingBuilder.Resources. - El recurso
webfrontend
se usa para llamar a GetEnvironmentVariableValuesAsync para recuperar sus variables de entorno configuradas. - El argumento DistributedApplicationOperation.Publish se pasa al llamar a
GetEnvironmentVariableValuesAsync
para especificar variables de entorno que se publican en el recurso como expresiones de enlace. - Con las variables de entorno devueltas, la prueba afirma que el recurso
webfrontend
tiene una variable de entorno HTTPS que se resuelve en el recurso deapiservice
.
Resumen
La plantilla de proyecto de prueba .NET Aspire facilita la creación de proyectos de prueba para soluciones de .NET Aspire. El proyecto de plantilla incluye una prueba de ejemplo que puede usar como punto de partida para las pruebas. El DistributedApplicationTestingBuilder
sigue un patrón familiar al WebApplicationFactory<TEntryPoint> en ASP.NET Core. Permite crear un host de prueba para la aplicación distribuida y ejecutar pruebas en ella.
Por último, al usar el DistributedApplicationTestingBuilder
todos los registros de recursos se redirigen al DistributedApplication
de forma predeterminada. La redirección de los registros de recursos permite escenarios en los que se desea verificar que un recurso está registrando correctamente.