如何以开发人员友好的方式针对 .NET 5.0 服务器测试 .NET 4.8 客户端 运行?
How to test a .NET 4.8 client running against a .NET 5.0 server in a developer-friendly way?
我不知道这个问题是否适合这个论坛。
我正在开发一个 C# ASP.NET 核心网络服务 和 使用此网络服务的客户端库。此时,服务器端部分和客户端部分的代码都位于同一个 Git 存储库和 Visual Studio 解决方案中。服务器部分旨在 运行 在 Azure 中。
我结合了单元测试和集成测试,包括同时测试客户端和服务器的端到端集成测试。我已经编写了测试,可以 运行 客户端(取决于配置)针对 Azure 中的服务器实例(具有注入的 URI)或针对使用 的本地内存服务器实例Microsoft.AspNetCore.TestHost.
效果很好。内存中的服务器实例在编码时非常方便。我们的持续集成 (Jenkins) 服务器 运行s 是针对云部署服务器(即已部署到 Azure 的 ASP.NET 核心网络服务的一个实例)的集成测试。这种针对云的测试提供了重要价值,但在本地编码时太麻烦了。
问题来了:服务器旨在 运行 在 .NET 5 上。客户端部分需要能够在 .NET Framework 4.8 和 .NET 5 上 运行。我们想要测试客户端 运行ning 4.8 是否可以针对服务器 运行ning .NET 5 正常工作(即我们的 ASP.NET Core webservice 的实例已针对 .NET 5 编译).
当然可以 运行 使用 .NET 4.8 针对使用 .NET 5 的云部署服务器进行集成测试。
可能不可能 - 或者至少不方便 - 在本地 运行 这些测试(因为相同的测试过程必须 运行 .NET 4.8 和 .NET 5)。但我想我们可以接受。
当然,我可以针对 .NET 5 构建服务器部分并将其部署到服务器,然后 运行 针对它进行一次集成测试。但这并不能解决我的长期问题。我希望能够定期 运行 all 我的集成测试。更具体地说,我想实现的是:
- 使用 .NET 5 客户端针对本地托管的 .NET 5 服务器(如今天)在本地 运行 集成测试应该很容易。
- Jenkins 服务器应该 运行 与 .NET 5 客户端针对云部署的 .NET 5 服务器(如今天)进行集成测试。
- Jenkins 服务器还应该 运行 与 .NET 4.8 客户端针对云部署的 .NET 5 服务器进行集成测试。
- 我不想维护两组测试。我希望在所有 3 种情况下 运行 所有相同的测试变得容易。
我可以通过复制我的集成测试项目并让这个新项目以 .NET 4.8 为目标并始终 运行 针对云来实现 1-3。但这意味着要维持两组测试。
您对我如何实现所有 4 个目标有什么建议吗?
提前致谢!
编辑 1:关于平台:我们的开发机器和 Jenkins 主机 运行 Windows。云部署的服务器还在 Windows 上 运行。
编辑 2:简单地多目标测试项目(即,让测试项目针对 .NET 4.8 和 .NET 5 进行编译)是不可能的。测试项目有对服务器部分的引用,因为它需要能够在本地运行服务器。服务器部分需要 .NET 5;它无法针对 .NET 4.8 进行编译(它依赖于 .NET 4.8 不存在的库)。因此,测试项目也无法针对 .NET 4.8 进行编译。
我最终按照@vernou 的建议使用预处理器指令解决了它。
我有以下项目:
- ClientLibrary - 调用网络服务的包装器。
- WebAPI - Web 服务的服务器端实现。
- IntegrationTest - 集成测试。
我的集成测试 CSPROJ 包含以下内容:
<PropertyGroup>
<TargetFrameworks>netframework4.8;net5.0</TargetFrameworks>
</PropertyGroup>
<!-- NuGet packages that we always need -->
<ItemGroup>
<PackageReference Include="Xunit.SkippableFact" Version="1.4.13" />
</ItemGroup>
<!-- NuGet packages that require .NET 5 -->
<ItemGroup Condition=" '$(TargetFramework)' == 'net5.0'">
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="5.0.3" />
</ItemGroup>
<!-- Project references that we always need -->
<ItemGroup>
<ProjectReference Include="ClientLibrary.csproj" />
</ItemGroup>
<!-- Project references that require .NET 5 -->
<ItemGroup Condition=" '$(TargetFramework)' == 'net5.0'">
<ProjectReference Include="WebAPI.csproj" />
</ItemGroup>
我的 Jenkinsfile 设置了一个环境变量以指向我的云应用程序的 Azure 部署实例:
def deployed_uri = powershell (
script: "pulumi stack output EndPoint",
returnStdout: true
)
env.integrationtest_service_uri = deployed_uri
我的测试是这样的:
private IService CreateService(Uri? uri)
{
if (uri is null)
{
// This is a built-in preprocessor directive: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/preprocessor-directives
#if NET5_0
_output.WriteLine("Connecting to locally hosted service");
return CreateLocallyHostedService();
#else
throw new JenkinsOnlyIntegrationTestException(
"Cannot start service because URI is null; we will assume that this test is only intended to run on Jenkins");
#endif
}
else
{
_output.WriteLine($"Connecting to service on URI: {uri}");
return CreateServiceAgainstRemoteUri(uri);
}
}
[SkippableFact(typeof(JenkinsOnlyIntegrationTestException))]
public void TestThatServiceWorks(){
var uri = GetUriOrNullFromEnvironmentVariableSetByJenkins()
var service = CreateService(uri);
// Test the service.
}
这样:
- 如果设置了环境变量 integrationtest_service_uri,集成测试将 运行 针对该地址的(云托管)服务器实例。
- 如果未设置环境变量且框架为 .NET 5,集成测试将 运行 使用 Microsoft.AspNetCore.TestHost 针对本地托管服务器.
- 如果没有设置环境变量,框架是.NET 4.8,测试会抛出异常,但是因为测试标记为[SkippableFact],所以会被计为跳过而不是失败。
我不知道这个问题是否适合这个论坛。
我正在开发一个 C# ASP.NET 核心网络服务 和 使用此网络服务的客户端库。此时,服务器端部分和客户端部分的代码都位于同一个 Git 存储库和 Visual Studio 解决方案中。服务器部分旨在 运行 在 Azure 中。
我结合了单元测试和集成测试,包括同时测试客户端和服务器的端到端集成测试。我已经编写了测试,可以 运行 客户端(取决于配置)针对 Azure 中的服务器实例(具有注入的 URI)或针对使用 的本地内存服务器实例Microsoft.AspNetCore.TestHost.
效果很好。内存中的服务器实例在编码时非常方便。我们的持续集成 (Jenkins) 服务器 运行s 是针对云部署服务器(即已部署到 Azure 的 ASP.NET 核心网络服务的一个实例)的集成测试。这种针对云的测试提供了重要价值,但在本地编码时太麻烦了。
问题来了:服务器旨在 运行 在 .NET 5 上。客户端部分需要能够在 .NET Framework 4.8 和 .NET 5 上 运行。我们想要测试客户端 运行ning 4.8 是否可以针对服务器 运行ning .NET 5 正常工作(即我们的 ASP.NET Core webservice 的实例已针对 .NET 5 编译).
当然可以 运行 使用 .NET 4.8 针对使用 .NET 5 的云部署服务器进行集成测试。
可能不可能 - 或者至少不方便 - 在本地 运行 这些测试(因为相同的测试过程必须 运行 .NET 4.8 和 .NET 5)。但我想我们可以接受。
当然,我可以针对 .NET 5 构建服务器部分并将其部署到服务器,然后 运行 针对它进行一次集成测试。但这并不能解决我的长期问题。我希望能够定期 运行 all 我的集成测试。更具体地说,我想实现的是:
- 使用 .NET 5 客户端针对本地托管的 .NET 5 服务器(如今天)在本地 运行 集成测试应该很容易。
- Jenkins 服务器应该 运行 与 .NET 5 客户端针对云部署的 .NET 5 服务器(如今天)进行集成测试。
- Jenkins 服务器还应该 运行 与 .NET 4.8 客户端针对云部署的 .NET 5 服务器进行集成测试。
- 我不想维护两组测试。我希望在所有 3 种情况下 运行 所有相同的测试变得容易。
我可以通过复制我的集成测试项目并让这个新项目以 .NET 4.8 为目标并始终 运行 针对云来实现 1-3。但这意味着要维持两组测试。
您对我如何实现所有 4 个目标有什么建议吗?
提前致谢!
编辑 1:关于平台:我们的开发机器和 Jenkins 主机 运行 Windows。云部署的服务器还在 Windows 上 运行。
编辑 2:简单地多目标测试项目(即,让测试项目针对 .NET 4.8 和 .NET 5 进行编译)是不可能的。测试项目有对服务器部分的引用,因为它需要能够在本地运行服务器。服务器部分需要 .NET 5;它无法针对 .NET 4.8 进行编译(它依赖于 .NET 4.8 不存在的库)。因此,测试项目也无法针对 .NET 4.8 进行编译。
我最终按照@vernou 的建议使用预处理器指令解决了它。
我有以下项目:
- ClientLibrary - 调用网络服务的包装器。
- WebAPI - Web 服务的服务器端实现。
- IntegrationTest - 集成测试。
我的集成测试 CSPROJ 包含以下内容:
<PropertyGroup>
<TargetFrameworks>netframework4.8;net5.0</TargetFrameworks>
</PropertyGroup>
<!-- NuGet packages that we always need -->
<ItemGroup>
<PackageReference Include="Xunit.SkippableFact" Version="1.4.13" />
</ItemGroup>
<!-- NuGet packages that require .NET 5 -->
<ItemGroup Condition=" '$(TargetFramework)' == 'net5.0'">
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="5.0.3" />
</ItemGroup>
<!-- Project references that we always need -->
<ItemGroup>
<ProjectReference Include="ClientLibrary.csproj" />
</ItemGroup>
<!-- Project references that require .NET 5 -->
<ItemGroup Condition=" '$(TargetFramework)' == 'net5.0'">
<ProjectReference Include="WebAPI.csproj" />
</ItemGroup>
我的 Jenkinsfile 设置了一个环境变量以指向我的云应用程序的 Azure 部署实例:
def deployed_uri = powershell (
script: "pulumi stack output EndPoint",
returnStdout: true
)
env.integrationtest_service_uri = deployed_uri
我的测试是这样的:
private IService CreateService(Uri? uri)
{
if (uri is null)
{
// This is a built-in preprocessor directive: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/preprocessor-directives
#if NET5_0
_output.WriteLine("Connecting to locally hosted service");
return CreateLocallyHostedService();
#else
throw new JenkinsOnlyIntegrationTestException(
"Cannot start service because URI is null; we will assume that this test is only intended to run on Jenkins");
#endif
}
else
{
_output.WriteLine($"Connecting to service on URI: {uri}");
return CreateServiceAgainstRemoteUri(uri);
}
}
[SkippableFact(typeof(JenkinsOnlyIntegrationTestException))]
public void TestThatServiceWorks(){
var uri = GetUriOrNullFromEnvironmentVariableSetByJenkins()
var service = CreateService(uri);
// Test the service.
}
这样:
- 如果设置了环境变量 integrationtest_service_uri,集成测试将 运行 针对该地址的(云托管)服务器实例。
- 如果未设置环境变量且框架为 .NET 5,集成测试将 运行 使用 Microsoft.AspNetCore.TestHost 针对本地托管服务器.
- 如果没有设置环境变量,框架是.NET 4.8,测试会抛出异常,但是因为测试标记为[SkippableFact],所以会被计为跳过而不是失败。