【问题标题】:How to test .NET Standard AND Core versions of a library properly?如何正确测试库的 .NET Standard 和 Core 版本?
【发布时间】:2020-01-29 16:17:04
【问题描述】:

背景:

我有一个库,它同时针对 .NET Standard 2.0 和 .NET Core(以及其他)。由于 .NET Standard 2.0 缺少 .NET Core/Framework 中存在的许多功能,我从 .NET Standard 2.0 版本中的许多成员那里抛出了PlatformNotSupportedException

问题 1:

UnitTest 项目不能以 .NET Standard 为目标,因此在测试项目中,我将 .NET Core 2.0 用于 .NET Core 和 Standard 版本。

在库 .csproj 中,我需要手动更改目标:

library.csproj:
<PropertyGroup>
  <!-- Compiles everything; for testing everything but .NET Standard 2.0 -->
  <TargetFrameworks>net35;net40;net45;netcoreapp2.0;netstandard2.0;netstandard2.1</TargetFrameworks>
  <!-- For testing .NET Standard 2.0: -->
  <!--<TargetFrameworks>netstandard2.0</TargetFrameworks>-->
</PropertyGroup>

test.csproj:
<PropertyGroup>
  <!-- now 'netcoreapp2.0' references either the .NET Core 2.0 or Standard 2.0 version depending on library.csproj -->
  <TargetFrameworks>net35;net40;net45;netcoreapp2.0;netcoreapp3.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
  <ProjectReference Include="..\library\library.csproj" />
</ItemGroup>

问题 2:

考虑到单元测试项目不能以 .NET Standard 为目标,此代码不起作用:

[Test]
public void TestSomethingThatIsNotAvailableInNetStandard20()
{
    TestDelegate testCode = () => ...;

#if NETSTANDARD2_0 // This is never true
    Assert.Throws<PlatformNotSupportedException>(testCode);
#else
    Assert.DoesNotThrow(testCode);
#endif
}

相反,现在我使用这样的东西:

[Test]
public void TestSomethingThatIsNotAvailableInNetStandard20()
{
    TestDelegate testCode = () => ...;

#if NETCOREAPP2_0 // .NET Core 2.0 OR .NET Standard 2.0
    if (IsNetStandard20)
        Assert.Throws<PlatformNotSupportedException>(testCode);
    else
        Assert.DoesNotThrow(testCode);
#else // all other targets
    Assert.DoesNotThrow(testCode);
#endif
}

...

// yikes... :/
public static bool IsNetStandard20 => typeof(SomeTypeFromMyLib).Assembly.GetReferencedAssemblies()
    .Any(an => an.Name == "netstandard" && an.Version == new Version(2, 0, 0, 0));

问题:

有没有办法在不更改 .csproj 文件的情况下测试 .NET Standard 2.0 版本(如果可能,可以去掉 IsNetStandard20 属性)?

免责声明:

我知道通常发布 .NET Standard 2.0 版本来支持 .NET Core 应用程序就足够了,但不幸的是,它缺少 .NET Core 2.0 所具有的许多功能(尽管这些功能包含在 .NET Standard 2.1 中,所以不需要单独的 .NET Core 3.0 版本)。

【问题讨论】:

  • 除非有人可以详细说明如何以另一种方式实现您正在寻找的东西,否则请接受我的回答。 Afaik 今天没有其他方法可以解决您的问题。
  • 我赞成你的回答,但它不能解决我的问题。看来“没有办法”比“没有办法”更正确。

标签: c# unit-testing .net-core nunit .net-standard


【解决方案1】:

UnitTest 项目不能以 .NET Standard 为目标,因此在测试项目中,我将 .NET Core 2.0 用于 .NET Core 和 Standard 版本。

这种说法并不完全正确。单元测试项目可以针对 .NETStandard,但大多数测试平台无法找到或执行这些测试。

可以明确在 .NETCore 进程中测试针对 .NETCore 的代码。 另一方面,针对 .NETStandard 的代码只能在使用实现指定版本 .NETStandard 的运行时在进程中隐式进行测试。 如果您想测试后者,您需要在所有匹配的运行时上运行您的测试,您希望在您的库的消费者中看到它们的使用情况。

如果您想让您的单元测试项目以 .NETStandard 为目标,那么您应该查看Nuclear.Test。 这允许您针对 .NETStandard 构建单元测试,并让它们在实现您选择的 .NETStandard 版本的 .NETCore .NETFramework 版本上执行。

您可以按照您已有的方式将您的单元测试项目定位到 .NETStandard 2.0 和 .NETCoreApp 2.0。 您的测试将与您的第一个示例非常相似。

[TestMethod]
void TestSomethingThatIsNotAvailableInNetStandard20()
{
    TestDelegate testCode = () => ...;

#if NETSTANDARD2_0 // This is compiled into net standard test assembly
    Test.If.ThrowsException(testCode, out PlatformNotSupportedException ex);
    // Assert.Throws<PlatformNotSupportedException>(testCode);
#else // This is compiled into every other test assembly
    Test.IfNot.ThrowsException(testCode, out PlatformNotSupportedException ex);
    // Assert.DoesNotThrow(testCode);
#endif
}

这种方法将解决您所描述的问题。 但是,由于单元测试平台的变化,它可能会引入新的问题。

【讨论】:

  • 感谢您的回答。这次核试验看起来很有希望,因为它证明这个问题毕竟可以从根本上得到解决。不幸的是,我无法迁移到它,因为它的 API 和功能与 NUnit 有很大不同。不过我给你投了赞成票。不错的项目,谢谢。
  • 谢谢。我希望这种执行测试程序集的方式有一天会变成 vsts,这样我们都可以在 .NETStandard 中编写测试。
【解决方案2】:

在类似的情况下(出于与György Kőszeg 指出的相同原因),我有一个多目标 C# 库项目,在 csproj 中有以下条目:

<!-- All target frameworks go into the NuGet package -->
<TargetFrameworks>netstandard2.0;netstandard2.1;net461</TargetFrameworks>

对于我终于想出的测试项目:

<TargetFrameworks>net462;netcoreapp3.1;net5.0</TargetFrameworks>

<!-- Project reference for netstandard2.1 and net462 -->
<!-- net5.0 will test the netstandard2.1 assembly -->
<ItemGroup Condition=" '$(TargetFramework)' != 'netcoreapp3.1'">
    <ProjectReference Include="..\Path-To\ProjectToTest.csproj" />
</ItemGroup>

<!-- Add test configuration for netstandard2.0 assemblies -->
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp3.1'">
    <Reference Include="ProjectToTest">
        <HintPath>..\ProjectToTest\bin\$(Configuration)\netstandard2.0\ProjectToTest.dll</HintPath>
    </Reference>
    <!-- Include all package references of the netstandard2.0 assembly -->
    <PackageReference Include="System.Memory" Version="4.5.4" />
</ItemGroup>

正如您在 JetBrains dotCover 报告中看到的,这似乎有效。

不确定,这是否是为 netstandard2.0 netstandard2.1 运行测试的唯一(甚至是最佳)方法。硬编码的引用不好维护,但比每次测试运行手动更改 csproj 更可靠。

【讨论】:

    猜你喜欢
    • 2020-05-10
    • 1970-01-01
    • 1970-01-01
    • 2018-05-01
    • 1970-01-01
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 2017-05-12
    相关资源
    最近更新 更多