如何根据当前平台跳过 xUnit 中的特定测试

发布于 2024-10-07 02:09:08 字数 550 浏览 1 评论 0原文

  • 我有一个在 Windows 上构建的程序集,
  • 我想在 Linux 中的 mono 上运行 xUnit 测试。

然而,我发现虽然其中 400 个测试可以(按顺序)运行,但某些测试要么挂起 xUnit 运行程序,要么完全关闭它。

我不关心某些测试是否无法在Linux上运行,某些测试与DTC和一些我们不需要在那里支持的非托管guph有关。

然而,我真正想要的是对这些测试应用忽略,并在构建输出中正确标记测试被忽略的事实。

这个问题可以归结为我猜有许多可能的解决方案

  • 如何通过控制台运行程序在 xUnit 中运行特定测试? (我还没有找到这方面的文档,也许我只是看起来不够努力)
  • 是否可以采取其他方式并说“这是一个程序集,但请忽略这些特定测试”
  • 在这些测试上有一个属性有人提出了一种更好的方法,正式记录这些测试是特定于平台的 - 这可能吗?

如果我能够避免过多修改原始代码,那就太棒了,因为代码并不是我真正可以更改的,并且应用大量跨平台黑客可能不会太顺利。

  • I have an assembly that I've built on Windows
  • I want to run the xUnit tests on mono in Linux.

However, I have found that while 400 of these tests can run (in order), that certain tests either hang the xUnit runner, or bring it down entirely.

I don't care if certain tests are not able to run on Linux, certain tests are to do with the DTC and some unmanaged gumph that we don't need to support there.

What I do want however, is to apply an ignore to those tests, and have the fact that the test was ignored flagged properly in the build output.

The question can be boiled down to I guess a number of possible solutions

  • How do I run specific tests in xUnit via the console runner? (I haven't found documentation to this end, maybe I'm just not looking hard enough)
  • Is it possible to go the other way and say "Here is an assembly, please ignore these specific tests though"
  • Having an attribute on those tests has been suggested a better way, to formally document that these tests are platform specific - is this possible?

If I could avoid modifying the original code too much that would be grand, as the code isn't really mine to change, and applying lots of cross-platform hacks probably won't go down too well.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

北陌 2024-10-14 02:09:08

XUnit v2.0 现已推出。它直接支持可跳过的测试。使用:

[Fact (Skip = "specific reason")]

XUnit v2.0 is now available. Skippable tests are supported by it directly. Use:

[Fact (Skip = "specific reason")]
南街女流氓 2024-10-14 02:09:08

现在有一个新的选择。

添加 Nuget 包 SkippableFact,它允许您使用 [SkippableFact] 而不是 [Fact],您可以在测试中使用 Skip. 在运行时动态跳过测试。

例子:

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

    // Test Windows only functionality.
}

There is a new options now.

Add Nuget Package SkippableFact, which allows you to use [SkippableFact] instead of [Fact] and you can use Skip.<xyz> within a Tests to dynamically Skip the Test during runtime.

Example:

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

    // Test Windows only functionality.
}
不再让梦枯萎 2024-10-14 02:09:08

我会避免外部化跳过测试(即配置/命令文件,如果可能的话)。这在某种程度上不利于使测试易于运行且值得信赖。当其他人开始参与时,在代码中忽略测试是最安全的方法。

我可以看到很多选项,这里有两个涉及修改现有代码。

选项 1 - 最具侵入性的编译时平台检测

在 VS 解决方案中,定义另一个配置,该配置定义预编译器标志 MONOWIN (只是这样它是一个明确的标志,表明它用于在 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 http://stackoverflow.com/questions/721161
    /// </summary>
    /// <returns>True if being executed in Mono, false otherwise.</returns>
    public static bool IsRunningOnMono() {
        return Type.GetType("Mono.Runtime") != null;
    }
}

注意 1

xUnit 运行程序将运行一个方法两次,如果它标记有 [Fact] 和 <代码> [IgnoreOnMonoFact] 。 (CodeRush 不会这样做,在这种情况下我假设 xUnit 是正确的)。这意味着任何测试方法都必须将 [Fact] 替换为 [IgnoreOnMonoFact]

注意 2

CodeRush 测试运行程序仍然运行 [IgnoreOnMonoFact] 测试,但它确实忽略了 [Fact(Skip="reason")] 测试。我认为这是由于 CodeRush 反映了 xUnit,而不是在 xUnit 库的帮助下实际运行它。这与 xUnit runner 配合得很好。

I would avoid externalising skipping tests (i.e. a config/command file if it's possible). This somewhat goes against making the tests easy to run and trustworthy. Making the tests ignored in code is the safest approach when other people start to get involved.

I could see a number of options, here are two that involve modification of existing code.

Option 1 - Most intrusive, compile time platform detection

In the VS Solution, define another configuration that defines a precompiler flag MONOWIN (just so that it's explicitly a flag the says that it is for code compiled on Windows for use on Mono).

Then define an attribute that will make the test ignored when compiled for Mono:

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

It's actually hard to find any advantages to this method as it involves mocking with the original solution and adds another confiration that needs to be supported.

Option 2 - somewhat intrusive - runtime platform detection

Here is a similar solution to option1, except no separate configuration is required:

public class IgnoreOnMonoFactAttribute : FactAttribute {

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

Note 1

xUnit runner will run a method twice if it is marked with [Fact] and [IgnoreOnMonoFact]. (CodeRush doesn't do that, in this case I assume xUnit is correct). This means that any tests methods must have [Fact] replaced with [IgnoreOnMonoFact]

Note 2

CodeRush test runner still ran the [IgnoreOnMonoFact] test, but it did ignore the [Fact(Skip="reason")] test. I assume it is due to CodeRush reflecting xUnit and not actually running it with the aid of xUnit libraries. This works fine with xUnit runner.

如果没有你 2024-10-14 02:09:08

[Fact(Skip="reason")]

有效,但我更喜欢使用特征

[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,这无疑不是很好。

[Fact(Skip="reason")]

works but I prefer to use 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
}

usage

dotnet test --filter type=unit

this protects our builds from accidentally running integration tests that devs forgot to skip e.g. [Fact(Skip="Integration")], however it does require unit tests to "opt in" to CI by adding the correct traits which admittedly isn't great.

半枫 2024-10-14 02:09:08

多米尼克的解决方案通过以下代码对我有用:

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

    // Act

    // Assert

}

The Dominik's solution work for me by this code:

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

    // Act

    // Assert

}
无尽的现实 2024-10-14 02:09:08

您可以像这样使用此自定义属性

using System;
using System.Runtime.InteropServices;
using Xunit;

[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
public class OsFactAttribute : FactAttribute
{
    public OsFactAttribute(params string[] allowedPlatforms)
    {
        try
        {
            if (!Array.Exists(allowedPlatforms, platform => RuntimeInformation.IsOSPlatform(OSPlatform.Create(platform))))
                Skip = $"Skip, this is allowed only on '{string.Join(", ", allowedPlatforms)}' platforms";
        }
        catch { /* this will not be skipped */ }
    }
}

,并使用一个或多个操作系统名称

using System;
using System.Runtime.InteropServices;
using Xunit;


[OsFact(nameof(OSPlatform.Windows), nameof(OSPlatform.Linux))]
public void Get_Input_ShouldBeEqual()
{

}

。对于 TheoryAttribute

另请参阅:

https://josephwoodward.co.uk/2019/01/skipping-xunit-tests-based-on-runtime-conditions

You can use this custom attribute

using System;
using System.Runtime.InteropServices;
using Xunit;

[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
public class OsFactAttribute : FactAttribute
{
    public OsFactAttribute(params string[] allowedPlatforms)
    {
        try
        {
            if (!Array.Exists(allowedPlatforms, platform => RuntimeInformation.IsOSPlatform(OSPlatform.Create(platform))))
                Skip = 
quot;Skip, this is allowed only on '{string.Join(", ", allowedPlatforms)}' platforms";
        }
        catch { /* this will not be skipped */ }
    }
}

Like this, with one or more OS names

using System;
using System.Runtime.InteropServices;
using Xunit;


[OsFact(nameof(OSPlatform.Windows), nameof(OSPlatform.Linux))]
public void Get_Input_ShouldBeEqual()
{

}

The same can be done as well for TheoryAttribute

See also:

https://josephwoodward.co.uk/2019/01/skipping-xunit-tests-based-on-runtime-conditions

香草可樂 2024-10-14 02:09:08

使用事实属性对我有用,

public class FactSkipTest : FactAttribute
{
    private readonly string _reason = "Test skipped: Requires elevated privileges (Administrator mode) for execution."";

    public override string Skip => skipIfIsNotAdministrator() ? _reason : null;

    public bool skipIfIsNotAdministrator()
    {
        var identity = WindowsIdentity.GetCurrent();
        var principal = new WindowsPrincipal(identity);
        return !principal.IsInRole(WindowsBuiltInRole.Administrator);
    }
}

public class AdministrationRightsTests
{
    [FactSkipTest]
    void checkThatApplicationDoesNotExists()
   { 
     //some tests
   }
}

Using Fact Attribute works for me,

public class FactSkipTest : FactAttribute
{
    private readonly string _reason = "Test skipped: Requires elevated privileges (Administrator mode) for execution."";

    public override string Skip => skipIfIsNotAdministrator() ? _reason : null;

    public bool skipIfIsNotAdministrator()
    {
        var identity = WindowsIdentity.GetCurrent();
        var principal = new WindowsPrincipal(identity);
        return !principal.IsInRole(WindowsBuiltInRole.Administrator);
    }
}

public class AdministrationRightsTests
{
    [FactSkipTest]
    void checkThatApplicationDoesNotExists()
   { 
     //some tests
   }
}
蓝梦月影 2024-10-14 02:09:08

添加到之前有关 SkippableFact 的答案:请注意,每个测试仍然是构造的 - 构造函数正在运行。

如果基类构造函数中有耗时的代码,另一种方法是将特定于环境的测试用例收集在合适的文件中,并在构造函数中运行环境检查:

        if (!SupportsTemporalQueries())
            throw new SkipException("This test class only runs in environments support temporal queries");

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

To add to the previous answers regarding SkippableFact: Note that each of the tests are still constructed - the constructor is run.

If you have timeconsuming code in a base class constructor, an alternative is to gather environment-specific test cases in suitable files and run the environment check in the constructor:

        if (!SupportsTemporalQueries())
            throw new SkipException("This test class only runs in environments support temporal queries");

This can speed up the test run considerable. In our system we either extend a "generic" base test class (runs in all environments) or an environment-specific base test class. I find this easier to maintain than filtering in pipelines or other solutions.

朮生 2024-10-14 02:09:08

现在,这个问题已在 1.8 中得到解决 - 您可以根据特征进行过滤。请参阅此问题日志

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

This is now solved in 1.8 - you can filter on Traits. See this issue log.

Update: Traits work with the console runner but not MSBuild, I've added a feature request for this support.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文