如何以开发人员友好的方式针对 .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 我的集成测试。更具体地说,我想实现的是:

  1. 使用 .NET 5 客户端针对本地托管的 .NET 5 服务器(如今天)在本地 运行 集成测试应该很容易。
  2. Jenkins 服务器应该 运行 与 .NET 5 客户端针对云部署的 .NET 5 服务器(如今天)进行集成测试。
  3. Jenkins 服务器还应该 运行 与 .NET 4.8 客户端针对云部署的 .NET 5 服务器进行集成测试。
  4. 我不想维护两组测试。我希望在所有 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],所以会被计为跳过而不是失败。