撰寫您的第一個 .NET.NET Aspire 測試
在本文中,您將瞭解如何建立測試專案、撰寫測試,以及針對您的 .NET.NET Aspire 解決方案執行測試專案。 本文中的測試不是單元測試,而是功能或整合測試。 .NET .NET Aspire 包含數種 測試專案範本的變化, 可用來測試 .NET.NET Aspire 資源相依性及其通訊。 測試專案範本適用於 MSTest、NUnit 和 xUnit 測試架構,並包含可用來作為測試起點的範例測試。
.NET .NET Aspire 測試項目樣板依賴於 📦Aspire.Hosting.Testing NuGet 套件。 此套件會公開 DistributedApplicationTestingBuilder 類別,用來為分散式應用程式建立測試主機。 分散式應用程式測試產生器依賴 DistributedApplication 類別來建立和啟動 應用程式主機。
建立測試專案
建立 .NET.NET Aspire 測試專案最簡單的方式是使用測試項目範本。 如果您要啟動新的 .NET.NET Aspire 專案,而且想要包含測試專案,Visual Studio 工具支援該選項。 如果您要將測試專案新增至現有的 .NET.NET Aspire 專案,您可以使用 dotnet new
命令來建立測試專案:
dotnet new aspire-xunit
dotnet new aspire-mstest
dotnet new aspire-nunit
如需詳細資訊,請參閱 .NET CLI dotnet new 命令檔。
探索測試專案
下列範例測試專案已建立為 .NET.NET Aspire 入門應用程式 範本的一部分。 如果您不熟悉,請參閱 快速入門:建置您的第一個 .NET.NET Aspire 專案。 .NET .NET Aspire 測試專案會在目標應用程式主機上建立專案參考的相依關係。 請考慮樣本專案:
<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="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>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>
上述項目檔相當標準。 有一個 PackageReference
給 📦Aspire的 .Hosting.Testing NuGet 套件,其中包含撰寫 .NET.NET Aspire 項目測試所需的類型。
範本測試專案包含一個 IntegrationTest1
類別和單一測試。 測試會驗證下列案例:
- 已成功建立並啟動應用程式主機。
-
webfrontend
資源可供使用並正常運行。 - 您可以對
webfrontend
資源提出 HTTP 要求,並傳回成功的回應 (HTTP 200 OK)。
請考慮下列測試類別:
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));
}
}
上述程式代碼:
- 依賴 DistributedApplicationTestingBuilder.CreateAsync API 以異步方式建立應用程式主機。
-
appHost
是代表應用程式主機的IDistributedApplicationTestingBuilder
實例。 -
appHost
實例已使用標準 HTTP 復原處理程式設定其服務集合。 如需詳細資訊,請參閱 建置復原性 HTTP 應用程式:的主要開發模式。
-
-
appHost
已叫用其 IDistributedApplicationTestingBuilder.BuildAsync(CancellationToken) 方法,它會傳回DistributedApplication
實例做為app
。-
app
的服務提供者取得了 ResourceNotificationService 實例。 -
app
是以異步方式啟動。
-
- 呼叫
app.CreateHttpClient
,為webfrontend
資源建立 HttpClient。 -
resourceNotificationService
可用來等候webfrontend
資源可供使用並執行。 - 對
webfrontend
資源的根目錄發出簡單的 HTTP GET 要求。 - 測試確認回應的狀態代碼是
OK
。
測試資源環境變數
若要進一步測試資源及其在 .NET.NET Aspire 解決方案中的表示相依性,您可以判斷是否正確地插入環境變數。 下列範例示範如何測試 webfrontend
資源是否有解析為 apiservice
資源的 HTTPS 環境變數:
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}")));
}
}
上述程式代碼:
- 依賴 DistributedApplicationTestingBuilder.CreateAsync API 以異步方式建立應用程式主機。
-
builder
實例可用來從 IDistributedApplicationTestingBuilder.Resources擷取名為 “webfrontend” 的 IResourceWithEnvironment 實例。 -
webfrontend
資源可用來呼叫 GetEnvironmentVariableValuesAsync 來擷取其設定的環境變數。 - 呼叫
GetEnvironmentVariableValuesAsync
時會傳遞 DistributedApplicationOperation.Publish 引數,以指定發佈至資源的環境變數,這些變數作為綁定運算式。 - 使用傳回的環境變數,測試判斷提示
webfrontend
資源具有解析為apiservice
資源的 HTTPS 環境變數。
總結
.NET Aspire 測試專案範本可讓您更輕鬆地建立 .NET Aspire 解決方案的測試專案。 範本專案包含可用來作為測試起點的範例測試。
DistributedApplicationTestingBuilder
遵循 ASP.NET Core中 WebApplicationFactory<TEntryPoint> 的熟悉模式。 它可讓您為分散式應用程式建立測試主機,並針對它執行測試。
最後,使用 DistributedApplicationTestingBuilder
預設會將所有資源記錄重新導向至 DistributedApplication
。 資源記錄的重新導向使您能夠在您希望驗證資源是否正確記錄的情境下,達到目的。
另請參閱
- 在 .NET 中使用 dotnet test 和 xUnit 單元測試 C#
- MSTest 概觀
- 使用 NUnit 和
Core 單元測試 C#