Napište svůj první test .NET.NET Aspire
V tomto článku se dozvíte, jak vytvořit testovací projekt, psát testy a spouštět je pro vaše .NET.NET Aspire řešení. Testy v tomto článku nejsou testy jednotek, ale spíše funkční nebo integrační testy. .NET .NET Aspire obsahuje několik variant testovacích šablon projektů, které můžete použít k testování závislostí .NET.NET Aspire prostředků a komunikace mezi nimi. Šablony testovacích projektů jsou k dispozici pro testovací architektury MSTest, NUnit a xUnit a obsahují ukázkový test, který můžete použít jako výchozí bod pro testy.
Šablony .NET.NET Aspire testovacích projektů spoléhají na 📦Aspire. Hosting.Testing balíčku NuGet. Tento balíček zveřejňuje DistributedApplicationTestingBuilder třídu, která slouží k vytvoření testovacího hostitele pro vaši distribuovanou aplikaci. Tvůrce pro testování distribuovaných aplikací spoléhá na třídu
Vytvoření testovacího projektu
Nejjednodušší způsob, jak vytvořit .NET.NET Aspire testovací projekt, je použít šablonu testovacího projektu. Pokud spouštíte nový projekt .NET.NET Aspire a chcete zahrnout projekty testů, nástroje Visual Studio tuto možnost podporují. Pokud přidáváte testovací projekt do existujícího projektu .NET.NET Aspire, můžete k vytvoření testovacího projektu použít příkaz dotnet new
:
dotnet new aspire-xunit
dotnet new aspire-mstest
dotnet new aspire-nunit
Další informace najdete v dokumentaci k příkazu .NET CLI dotnet new.
Prozkoumání testovacího projektu
Následující ukázkový testovací projekt byl vytvořen jako součást šablony .NET.NET Aspire Starter Application. Pokud nejste s tímto obeznámeni, přečtěte si rychlý průvodce: Vytvořte svůj první .NET.NET Aspire projekt. Testovací projekt .NET.NET Aspire využívá závislost odkazu na projekt na hostitele cílové aplikace. Zvažte projekt šablony:
<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>
Předchozí soubor projektu je poměrně standardní. Existuje balíček NuGet .Hosting.Testing, který zahrnuje požadované typy pro psaní testů pro projekty
Projekt testu šablony obsahuje třídu IntegrationTest1
s jedním testem. Test ověří následující scénář:
- Hostitel aplikace se úspěšně vytvořil a spustil.
- Prostředek
webfrontend
je dostupný a spuštěný. - HTTP požadavek lze směrovat na prostředek
webfrontend
a vrátí úspěšnou odpověď (HTTP 200 OK).
Vezměte v úvahu následující testovací třídu:
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));
}
}
Předchozí kód:
- Spoléhá na rozhraní DistributedApplicationTestingBuilder.CreateAsync API k asynchronnímu vytvoření hostitele aplikace.
-
appHost
je instanceIDistributedApplicationTestingBuilder
, která představuje hostitele aplikace. - Instance
appHost
má svou kolekci služeb nakonfigurovanou standardní obslužnou rutinou odolnosti HTTP. Další informace najdete v tématu Vytváření odolných aplikací HTTP: Klíčové vývojové vzory.
-
-
appHost
má vyvolánu metodu IDistributedApplicationTestingBuilder.BuildAsync(CancellationToken), která vrátí instanciDistributedApplication
jakoapp
.-
app
má poskytovatele služby, který získá instanci ResourceNotificationService. -
app
se spouští asynchronně.
-
- Voláním HttpClientse vytvoří
webfrontend
pro prostředekapp.CreateHttpClient
. -
resourceNotificationService
slouží k čekání na dostupnost a spuštění prostředkuwebfrontend
. - Jednoduchý požadavek HTTP GET se provádí v kořenovém adresáři prostředku
webfrontend
. - Test tvrdí, že stavový kód odpovědi je
OK
.
Testování proměnných prostředí zdrojů
Pokud chcete dále testovat prostředky a jejich vyjádřené závislosti v řešení .NET.NET Aspire, můžete ověřit, že proměnné prostředí se správně vloží. Následující příklad ukazuje, jak otestovat, že prostředek webfrontend
má proměnnou prostředí HTTPS, která odkazuje na prostředek 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}")));
}
}
Předchozí kód:
- Spoléhá na rozhraní DistributedApplicationTestingBuilder.CreateAsync API k asynchronnímu vytvoření hostitele aplikace.
- Instance
builder
slouží k načtení instance IResourceWithEnvironment s názvem "webfrontend" z IDistributedApplicationTestingBuilder.Resources. - Prostředek
webfrontend
slouží k volání GetEnvironmentVariableValuesAsync k načtení nakonfigurovaných proměnných prostředí. - Argument DistributedApplicationOperation.Publish se předá při volání
GetEnvironmentVariableValuesAsync
k určení proměnných prostředí, které jsou publikovány do prostředku jako vazbové výrazy. - Při vrácených proměnných prostředí test tvrdí, že prostředek
webfrontend
má proměnnou prostředí HTTPS, která se přeloží na prostředekapiservice
.
Shrnutí
Šablona projektu .NET Aspire testování usnadňuje vytváření testovacích projektů pro .NET Aspire řešení. Projekt šablony obsahuje ukázkový test, který můžete použít jako výchozí bod pro testy.
DistributedApplicationTestingBuilder
následuje známý vzor jako WebApplicationFactory<TEntryPoint> v ASP.NET Core. Umožňuje vytvořit testovacího hostitele pro distribuovanou aplikaci a spouštět s ní testy.
Nakonec při použití DistributedApplicationTestingBuilder
všechny protokoly prostředků se ve výchozím nastavení přesměrují na DistributedApplication
. Přesměrování protokolů prostředků umožňuje scénáře, ve kterých chcete ověřit, že se prostředek správně protokoluje.