Rédigez votre premier test de .NET.NET Aspire
Dans cet article, vous allez apprendre à créer un projet de test, à écrire des tests et à les exécuter pour vos solutions .NET.NET Aspire. Les tests de cet article ne sont pas des tests unitaires, mais plutôt des tests fonctionnels ou d’intégration. .NET .NET Aspire comprend plusieurs variantes de modèles de projet de test que vous pouvez utiliser pour tester vos dépendances de ressources .NET.NET Aspire et leurs communications. Les modèles de projet de test sont disponibles pour les frameworks de test MSTest, NUnit et xUnit et incluent un exemple de test que vous pouvez utiliser comme point de départ pour vos tests.
Les modèles de projet de test .NET.NET Aspire s’appuient sur le package NuGet 📦Aspire. Hosting.Testing. Ce package expose la classe DistributedApplicationTestingBuilder, qui est utilisée pour créer un hôte de test pour votre application distribuée. Le générateur de tests d’applications distribués s’appuie sur la classe DistributedApplication pour créer et démarrer l’hôte d’application .
Créer un projet de test
Le moyen le plus simple de créer un projet de test .NET.NET Aspire consiste à utiliser le modèle de projet de test. Si vous démarrez un nouveau projet .NET.NET Aspire et que vous souhaitez inclure des projets de test, l’outil Visual Studio prend en charge cette option. Si vous ajoutez un projet de test à un projet de .NET.NET Aspire existant, vous pouvez utiliser la commande dotnet new
pour créer un projet de test :
dotnet new aspire-xunit
dotnet new aspire-mstest
dotnet new aspire-nunit
Pour plus d’informations, consultez la documentation de la .NET CLI dotnet new command.
Explorer le projet de test
L’exemple de projet de test suivant a été créé dans le cadre du modèle d'application de démarrage .NET.NET Aspire. Si vous ne le connaissez pas, consultez Démarrage rapide : Construire votre premier projet .NET.NET Aspire. Le projet de test .NET.NET Aspire utilise une dépendance de référence de projet sur l’hôte d’application cible. Considérez le projet de modèle :
<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.6.4" />
</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.0" />
<PackageReference Include="NUnit.Analyzers" Version="4.4.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>
Le fichier projet précédent est assez standard. Il y a un PackageReference
au 📦Aspire. Hosting.Testing package NuGet, qui inclut les types requis pour écrire des tests pour .NET.NET Aspire projets.
Le projet de test de modèle inclut une classe IntegrationTest1
avec un seul test. Le test vérifie le scénario suivant :
- L’hôte de l’application a été créé avec succès et démarré.
- La ressource
webfrontend
est disponible et en cours d’exécution. - Une requête HTTP peut être envoyée à la ressource
webfrontend
et retourne une réponse réussie (HTTP 200 OK).
Considérez la classe de test suivante :
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));
}
}
Code précédent :
- S’appuie sur l’API DistributedApplicationTestingBuilder.CreateAsync pour créer de façon asynchrone l’hôte d’application.
- Le
appHost
est une instance deIDistributedApplicationTestingBuilder
qui représente l’hôte de l’application. - L’instance
appHost
a sa collection de services configurée avec le gestionnaire de résilience HTTP standard. Pour plus d’informations, consultez Créer des applications HTTP résilientes : modèles de développement clés.
- Le
- La méthode IDistributedApplicationTestingBuilder.BuildAsync(CancellationToken) de
appHost
est invoquée, qui retourne l’instanceDistributedApplication
en tant queapp
.- Le
app
fait en sorte que son fournisseur de services obtienne l’instance ResourceNotificationService. - La
app
est démarrée de façon asynchrone.
- Le
- Un HttpClient est créé pour la ressource
webfrontend
en appelantapp.CreateHttpClient
. - Le
resourceNotificationService
est utilisé pour attendre que la ressourcewebfrontend
soit disponible et en cours d’exécution. - Une requête HTTP GET simple est effectuée à la racine de la ressource
webfrontend
. - Le test affirme que le code d’état de la réponse est
OK
.
Tester les variables d’environnement de ressources
Pour tester davantage les ressources et leurs dépendances exprimées dans votre solution .NET.NET Aspire, vous pouvez affirmer que les variables d’environnement sont injectées correctement. L’exemple suivant montre comment tester que la ressource webfrontend
a une variable d’environnement HTTPS qui se résout vers la ressource 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}")));
}
}
Code précédent :
- S’appuie sur l’API DistributedApplicationTestingBuilder.CreateAsync pour créer de façon asynchrone l’hôte d’application.
- L’instance
builder
est utilisée pour récupérer une instance de IResourceWithEnvironment nommée « webfrontend » à partir du IDistributedApplicationTestingBuilder.Resources. - La ressource
webfrontend
est utilisée pour appeler GetEnvironmentVariableValuesAsync pour récupérer ses variables d’environnement configurées. - L’argument DistributedApplicationOperation.Publish est passé lors de l’appel de
GetEnvironmentVariableValuesAsync
pour spécifier des variables d’environnement publiées dans la ressource en tant qu’expressions de liaison. - Avec les variables d’environnement retournées, le test affirme que la ressource
webfrontend
a une variable d’environnement HTTPS qui se résout vers la ressourceapiservice
.
Résumé
Le modèle de projet de test .NET Aspire facilite la création de projets de test pour .NET Aspire solutions. Le projet de modèle inclut un exemple de test que vous pouvez utiliser comme point de départ pour vos tests. Le DistributedApplicationTestingBuilder
suit un modèle familier à l'WebApplicationFactory<TEntryPoint> dans ASP.NET Core. Il vous permet de créer un hôte de test pour votre application distribuée et d’exécuter des tests sur celui-ci.
Enfin, lors de l’utilisation de la DistributedApplicationTestingBuilder
tous les journaux de ressources sont redirigés vers le DistributedApplication
par défaut. La redirection des journaux de ressources permet des scénarios dans lesquels vous voulez vous assurer qu'une ressource journalise correctement.