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.
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.
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.
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.
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]
[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 ) }; } }
You can also search for SkippableFact in the Nugget Manager, then you can use all functions with [SkippableFact]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With