Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to dynamically skip a test with Xunit 2.0?

Tags:

xunit.net

Xunit 1.9.x provides the user with the DynamicSkipExample.cs example to help him setting up dynamic skipping of a [Fact].

This has proven to be quite useful when performing some cross-platform development. This allows a test to be temporarily ignored when it cannot be properly run because of the underlying context (OS, filesystem, ...).

However, this example has been dropped in commit 2deeff5 on the road to version 2.0.

How can one re-implement such a functionality through one of the extensibility points of Xunit 2.0?

Note: An issue about this topic has been raised in the xUnit tracker. See xunit/xunit#250.

like image 289
nulltoken Avatar asked Jan 03 '15 13:01

nulltoken


People also ask

How do I skip a test in xUnit?

xUnit.net does not require an attribute for a test class; it looks for all test methods in all public (exported) classes in the assembly. Set the Skip parameter on the [Fact] attribute to temporarily skip a test.

Does xUnit run tests in parallel?

Running unit tests in parallel is a new feature in xUnit.net version 2. There are two essential motivations that drove us to not only enable parallelization, but also for it to be a feature that's enabled by default: As unit testing has become more prevalent, so too have the number of unit tests.

What is xUnit runner Visualstudio?

xunit.runner.visualstudio. This package contains the VSTest runner. This runner is capable of running . NET Framework projects from xUnit.net v1 and v2, and . NET Core and UWP projects projects from xUnit.net v2.

Which of the following attributes are eliminated in xUnit?

Here is the list of attributes removed from the framework: [Setup] and [TearDown] are replaced with Constructors & IDisposable. [TestFixture] is removed. [Ignore] is absorbed with Skip = parameter on [Fact]


2 Answers

[Update: XUnit v2.0 (RTM) is now available and skippable tests are supported by it directly. Use [Fact (Skip = "specific reason")] ]

Note that XUnit v2.0 has not shipped. This example is compatible with Xunit 2.0 beta5 which you can find on nuget.org. There may be other ways to accomplish this (as this is just the example I came to).

1) Define an attribute that will decorate your tests.

/// <inheritdoc/> [AttributeUsage( AttributeTargets.Method, AllowMultiple = false )] [XunitTestCaseDiscoverer( "SkippableTestCaseDiscoverer", "assemblynamehere" )] public sealed class SkippableTestAttribute : FactAttribute {     public SkippableTestAttribute() { } }     

2) Create your discoverer. (We followed the code example at https://github.com/xunit/xunit/blob/2d9ce6fbd75e91a69a0cc83e1bc3d4eab18b2c6c/src/xunit.execution/Sdk/Frameworks/TheoryDiscoverer.cs)

/// <summary> /// Implementation of <see cref="IXunitTestCaseDiscoverer"/> that supports finding test cases /// on methods decorated with <see cref="SkippableTestAttribute"/>. /// </summary> public class SkippableTestCaseDiscoverer : IXunitTestCaseDiscoverer {     /// <inheritdoc/>     [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Needs to return test case." )]     public IEnumerable<IXunitTestCase> Discover( ITestMethod testMethod, IAttributeInfo factAttribute )     {         // some of this code is from https://github.com/xunit/xunit/blob/2d9ce6fbd75e91a69a0cc83e1bc3d4eab18b2c6c/src/xunit.execution/Sdk/Frameworks/TheoryDiscoverer.cs         if ( factAttribute.GetNamedArgument<string>( "Skip" ) != null )             return new[] { new XunitTestCase( testMethod ) };          var dataAttributes = testMethod.Method.GetCustomAttributes( typeof( DataAttribute ) );          try         {             var results = new List<XunitTestCase>();              foreach ( var dataAttribute in dataAttributes )             {                 var discovererAttribute = dataAttribute.GetCustomAttributes( typeof( DataDiscovererAttribute ) ).First();                 var discoverer = ExtensibilityPointFactory.GetDataDiscoverer( discovererAttribute );                 if ( !discoverer.SupportsDiscoveryEnumeration( dataAttribute, testMethod.Method ) )                     return new XunitTestCase[] { new XunitTheoryTestCase( testMethod ) };  // These lines are our "custom dynamic logic" that determines if we should skip the test.                 IEnumerable<object[]> data = discoverer.GetData( dataAttribute, testMethod.Method );                  if ( data == null )                 {                     var test = new SkippableTestCase( testMethod );                     test.SkipTest( "Test not configured with any " );                     return new[] { test };                 }                 foreach ( var dataRow in data )                 {                     // Attempt to serialize the test case, since we need a way to uniquely identify a test                     // and serialization is the best way to do that. If it's not serializable, this will                     // throw and we will fall back to a single theory test case that gets its data                     // at runtime.                     var testCase = new XunitTestCase( testMethod, dataRow );                     SerializationHelper.Serialize( testCase );                     results.Add( testCase );                 }             }              if ( results.Count == 0 )                 results.Add( new LambdaTestCase( testMethod,                                                () => { throw new InvalidOperationException( String.Format( "No data found for {0}.{1}", testMethod.TestClass.Class.Name, testMethod.Method.Name ) ); } ) );              return results;         }         catch         {             return new XunitTestCase[] { new XunitTheoryTestCase( testMethod ) };         }     } } 

3) Create a class which implements IXunitTestCase (as the default base class doesn't allow modifying the skip reason).

// Class is similar to XunitTestCase  [Serializable] public class SkippableTestCase : TestMethodTestCase, IXunitTestCase  {     [EditorBrowsable(EditorBrowsableState.Never)]     [Obsolete("Called by the de-serializer", error: true)]     public SkippableTestCase() { }      /// <summary>     /// Initializes a new instance of the <see cref="SkippableTestCase"/> class.     /// </summary>     /// <param name="testMethod">The test method this test case belongs to.</param>     /// <param name="testMethodArguments">The arguments for the test method.</param>     public SkippableTestCase(ITestMethod testMethod, object[] testMethodArguments = null)         : base(testMethod, testMethodArguments) { }      /// <inheritdoc />     protected SkippableTestCase(SerializationInfo info, StreamingContext context)         : base(info, context) { }      public void SkipTest( string reason )     {         base.SkipReason = reason;     }      /// <inheritdoc/>     public virtual Task<RunSummary> RunAsync( IMessageBus messageBus, object[] constructorArguments, ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource )     {         return new XunitTestCaseRunner( this, DisplayName, SkipReason, constructorArguments, TestMethodArguments, messageBus, aggregator, cancellationTokenSource ).RunAsync();     } } 

You have many options for how you want to set the base.SkipReason. In this sample, a public method was created.

This example will skip tests that have a MemberDataAttribute that returns no data rows. You can modify it to return the SkippableTestCase based on your criteria. For example, this discover skips tests on Sunday.

/// <inheritdoc/> [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Needs to return test case." )] public IEnumerable<IXunitTestCase> Discover( ITestMethod testMethod, IAttributeInfo factAttribute ) {     if ( DateTime.Today.DayOfWeek == DayOfWeek.Sunday )     {         var test = new SkippableTestCase( testMethod );         test.SkipTest( "Test not configured with any " );         return new[] { test };     }     else     {         return new[] { new XunitTestCase( testMethod ) };     } } 
like image 56
Matthew K Avatar answered Oct 01 '22 10:10

Matthew K


You can also search for SkippableFact in the Nugget Manager, then you can use all functions with [SkippableFact]

like image 29
Dominik Lemberger Avatar answered Oct 01 '22 11:10

Dominik Lemberger