如何在基于当前平台的xUnit中跳过特定测试

146
  • 我有一个在Windows上构建的程序集
  • 我想在Linux上通过Mono运行xUnit测试。

然而,我发现尽管其中400个测试可以(按顺序)运行,但某些测试会挂起xUnit运行器或完全使其崩溃。

针对那些不能在Linux上运行的测试,我不介意。其中一些测试与DTC以及我们不需要在那里支持的某些非托管东西有关。

但是,我希望能够忽略这些测试,并在生成的输出中正确标记被忽略的测试。

这个问题可以归结为可能有多种解决方案:

  • 如何通过控制台运行器在xUnit中运行特定的测试?(我还没有找到相关文档,也许我没有找得够仔细)
  • 是否有可能反过来说“这里是一个程序集,请忽略这些特定的测试”
  • 已经有人建议在那些测试上使用属性更好,以正式记录这些测试是特定于平台的-这是可能的吗?

如果我能尽可能地避免修改原始代码,那就太好了,因为这段代码并不真正属于我,而且应用许多跨平台的技巧可能不会取得好的效果。

7个回答

282

XUnit v2.0现在已经发布。它直接支持可跳过的测试。使用:

[Fact (Skip = "specific reason")]

7
如果您出于同一原因需要对多个测试应用跳过功能,那么可以将“Skip”字符串定义为常量。这样有助于避免重复、更易于发现以及提升代码可维护性等优点。 - Nicholas Petersen
5
注意,这也适用于带参数的测试 [Theory(Skip = "reason")] - user2051770
@user2051770 你知道在[Theory]内是否有一种不使用其他包就可以跳过单个测试的方法吗? - Nomnom

69

如果可能,我会避免外部化跳过测试(例如配置/命令文件)。这在使测试易于运行和可靠方面有所不利。当其他人开始参与时,忽略代码中的测试是最安全的方法。

我可以看到许多选项,以下是两个涉及修改现有代码的选项。

选项1-最深入的——编译时平台检测

在VS解决方案中,定义另一个配置,它定义了一个预编译器标记MONOWIN(只是为了明确地指出它是用于在Mono上使用的Windows上编译的代码的标记)。

然后定义一个属性,使得在编译为Mono时忽略该测试:

public class IgnoreOnMonoFactAttribute : FactAttribute {
#if MONOWIN
    public IgnoreOnMonoFactAttribute() {
        Skip = "Ignored on Mono";
    }
#endif
}

实际上很难找到这种方法的任何优点,因为它涉及对原始解决方案进行模拟,并添加了另一个需要支持的配置。

选项2 - 有些侵入性 - 运行时平台检测

这里有一个类似于选项1的解决方案,但不需要单独的配置:

public class IgnoreOnMonoFactAttribute : FactAttribute {

    public IgnoreOnMonoFactAttribute() {
        if(IsRunningOnMono()) {
            Skip = "Ignored on Mono";
        }
    }
    /// <summary>
    /// Determine if runtime is Mono.
    /// Taken from https://dev59.com/KXRB5IYBdhLWcg3wF0HH
    /// </summary>
    /// <returns>True if being executed in Mono, false otherwise.</returns>
    public static bool IsRunningOnMono() {
        return Type.GetType("Mono.Runtime") != null;
    }
}

注意1

如果使用[Fact][IgnoreOnMonoFact]标记方法,则xUnit运行器会将该方法运行两次(在这种情况下,CodeRush不会这样做,我认为xUnit是正确的)。这意味着任何测试方法必须用[IgnoreOnMonoFact]替换[Fact]

注意2

CodeRush测试运行器仍然运行了[IgnoreOnMonoFact]测试,但它忽略了[Fact(Skip="reason")]测试。我认为这是由于CodeRush反映了xUnit,而不是实际上使用xUnit库来运行它。这在xUnit运行器中可以正常工作。


我认为我可能需要使用定制事实,但是不确定项目的核心提交者会不会很高兴 :) - metdos
7
<���实(跳过:="我的原因")> _ 做得很好! - Brent
1
似乎无法与xunit.runner.visualstudio一起使用。还有其他人遇到这个问题吗? - marknuzz
1
这是我迄今为止找到的最干净、最好的答案。SkippableFact 的代码不够简洁,会增加依赖项,并且也无法描述为什么测试被跳过。 - Pellet
10年前的回答非常好,但截至目前为止已经不太适用了。 - No Refunds No Returns

69

现在有一个新的选项。

添加Nuget包SkippableFact,使您可以使用[SkippableFact]代替[Fact],并且您可以在测试中使用Skip.<xyz>来动态跳过测试。

示例:

[SkippableFact]
public void SomeTestForWindowsOnly()
{
    Skip.IfNot(Environment.IsWindows);

    // Test Windows only functionality.
}

2
优秀的软件包! - Karel Kral
1
感谢这个优秀的软件包。很遗憾这样基本的功能没有被包含在标准库中。 - DELUXEnized
额外说明:在当前版本的Nuget包SkippableFact中,也支持 [SkippableTheory] - h.m.i.13
附加说明:当前版本的Nuget包SkippableFact还支持[SkippableTheory] - undefined

8

[Fact(Skip="reason")]

这行代码可以工作,但我更喜欢使用traits。

[Fact, Trait("type","unit")]
public void MyUnitTest(){
  // given 
  // when
  // then
}

[Fact, Trait("type","http")]
public void MyHttpIntegrationTest(){
  // given 
  // when do things over HTTP
  // then
}

用法

dotnet test --filter type=unit

这可以保护我们的构建过程不会意外运行开发人员忘记跳过的集成测试,例如[Fact(Skip="Integration")],但是这确实要求单元测试通过添加正确的特征来“选择”CI,这并不是很好。


你好,你是否能够按“不等于”进行筛选?dotnet test --filter type~=unit似乎无效。 - liang
@liang !~ 不包含 查看文档 - wickdninja

3

Dominik的解决方案对我有用,代码如下:

[SkippableFact]
public void Get_WhenCall_ReturnsString()
{
    // Arrange
    Skip.IfNot(RuntimeInformation.IsOSPlatform(OSPlatform.Windows));

    // Act

    // Assert

}

这个答案似乎与Domink的代码相比没有增加价值。 - Matt Tsōnto
@MattTsōnto,Environment.IsWindows在一些应用程序中无法正常工作,开发人员应该使用RuntimeInformation.IsOSPlatform(OSPlatform.Windows)来代替它。 - Ramin Bateni

0
关于SkippableFact的先前回答,还需补充说明:请注意,每个测试仍然是构造的,即构造函数会运行。
如果您在基类构造函数中拥有耗时的代码,另一种选择是将特定于环境的测试用例收集到合适的文件中,并在构造函数中运行环境检查。
        if (!SupportsTemporalQueries())
            throw new SkipException("This test class only runs in environments support temporal queries");

这可以极大地加速测试运行。在我们的系统中,我们要么扩展一个“通用”的基本测试类(在所有环境中运行),要么扩展一个特定于环境的基本测试类。我发现这比在管道或其他解决方案中进行过滤更易于维护。


对我来说,这将使测试显示为失败。 - sommmen

-1

这个问题在1.8版本中已经解决了 - 您可以对特征进行过滤。请参见问题日志

更新:特征适用于控制台运行程序,但不适用于MSBuild,我已经添加了一个功能请求以支持此功能。


7
如果这篇回答除了链接和“特征”提到的信息还能包含更多内容,那么它将更有用。具体的链接已经失效。 - Pac0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接