How do I skip specific tests in xUnit based on current platform
Asked Answered
R

9

163
  • 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.

Romantic answered 12/12, 2010 at 11:4 Comment(0)
W
69

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.

Winnebago answered 12/12, 2010 at 13:44 Comment(5)
I think I might have to go with the custom fact, not entirely sure if the core committer on the project will be so happy though :)Romantic
<Fact(Skip:="My Reason")> _ Worked great!Hyperbaton
Seems to not work with xunit.runner.visualstudio. Anyone else getting this?Peag
This is the cleanest, best answer I have found so far. SkippableFact is not as clean with code and adds dependencies, and also does not allow for a description of why the test was skipped.Avian
Great answer 10 years ago. Not so much as of this writing.Offence
T
303

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

[Fact (Skip = "specific reason")]
Treasurehouse answered 21/6, 2016 at 7:36 Comment(3)
And if you need to apply skip to a number of tests for the same reason, nothing stops making the Skip string a constant. DRY, easier discoverability, etc.Inshore
Note this also works for parameterized tests [Theory (Skip = "reason")]Tailor
@Tailor Do you know if there's a way to skip individuals tests within the [Theory] without the use of an additional package?Dentition
P
72

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.
}
Pink answered 8/3, 2016 at 15:31 Comment(3)
Briliant package!Bathroom
Thanks for this great package. It is sad that such basic functionality is not included in the standard library.Nephritic
Additional note: [SkippableTheory] is also supported in the current version of the Nuget package SkippableFact.Solar
W
69

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.

Winnebago answered 12/12, 2010 at 13:44 Comment(5)
I think I might have to go with the custom fact, not entirely sure if the core committer on the project will be so happy though :)Romantic
<Fact(Skip:="My Reason")> _ Worked great!Hyperbaton
Seems to not work with xunit.runner.visualstudio. Anyone else getting this?Peag
This is the cleanest, best answer I have found so far. SkippableFact is not as clean with code and adds dependencies, and also does not allow for a description of why the test was skipped.Avian
Great answer 10 years ago. Not so much as of this writing.Offence
I
11

[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.

Illampu answered 6/1, 2022 at 21:52 Comment(2)
curious, would you be able to filter by "not equal"? dotnet test --filter type~=unit doesn't seem to workRosaliarosalie
@Rosaliarosalie !~ doesn't contain see docsIllampu
F
3

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

}
Funiculus answered 8/3, 2022 at 13:35 Comment(2)
This answer doesn't seem to add value compared to Domink's codeMicrominiaturization
@MattTsōnto, Environment.IsWindows does not work in some applications then developer should use RuntimeInformation.IsOSPlatform(OSPlatform.Windows) instead of it.Funiculus
T
2

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 = $"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

Trapeze answered 11/12, 2023 at 18:20 Comment(0)
P
0

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.

Philomel answered 29/3, 2022 at 9:8 Comment(1)
for me this will make it show the test as failedSoloist
F
0

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
   }
}
Fatback answered 19/2 at 16:25 Comment(0)
C
-1

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.

Conceptionconceptual answered 23/2, 2012 at 23:37 Comment(1)
This answer would be much more useful if it actually contained some more information than just a link and the Traits mention. The specific link is dead.Vamoose

© 2022 - 2024 — McMap. All rights reserved.