Skip to content

Instantly share code, notes, and snippets.

@safern
Last active January 14, 2021 21:57
Show Gist options
  • Save safern/30135f81c5361c815d7e189e4e40b8ba to your computer and use it in GitHub Desktop.
Save safern/30135f81c5361c815d7e189e4e40b8ba to your computer and use it in GitHub Desktop.
Custom xunit fact attribute to skip quarantined tests
namespace XunitExtensions
{
public class QuarantineDiscoverer : IXunitTestCaseDiscoverer
{
public QuarantineDiscoverer(IMessageSink diagnosticMessageSink)
{
DiagnosticMessageSink = diagnosticMessageSink;
}
public IMessageSink DiagnosticMessageSink { get; }
public IEnumerable<IXunitTestCase> Discover(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo factAttribute)
{
// Add logic here to get ActiveIssueAttribute and call it's discoverer to see if the conditions apply.
return new[] { new QuarantinedTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod) };
}
}
[XunitTestCaseDiscoverer("XunitExtensions.QuarantineDiscoverer", "MyTests")]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class CustomFact : FactAttribute
{
}
public class QuarantinedTestCase : XunitTestCase
{
[Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes", error: true)]
public QuarantinedTestCase() { }
public QuarantinedTestCase(IMessageSink diagnosticMessageSink, TestMethodDisplay defaultMethodDisplay, TestMethodDisplayOptions defaultMethodDisplayOptions, ITestMethod testMethod, object[] testMethodArguments = null)
: base(diagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testMethod, testMethodArguments) { }
public override async Task<RunSummary> RunAsync(IMessageSink diagnosticMessageSink,
IMessageBus messageBus,
object[] constructorArguments,
ExceptionAggregator aggregator,
CancellationTokenSource cancellationTokenSource)
{
QuarantinedTestMessageBus skipMessageBus = new QuarantinedTestMessageBus(messageBus);
var result = await base.RunAsync(diagnosticMessageSink, skipMessageBus, constructorArguments, aggregator, cancellationTokenSource);
if (skipMessageBus.SkippedTestCount > 0)
{
result.Failed -= skipMessageBus.SkippedTestCount;
result.Skipped += skipMessageBus.SkippedTestCount;
}
return result;
}
}
public class QuarantinedTestMessageBus : IMessageBus
{
readonly IMessageBus innerBus;
public QuarantinedTestMessageBus(IMessageBus innerBus)
{
this.innerBus = innerBus;
}
public int SkippedTestCount { get; private set; }
public void Dispose() { }
public bool QueueMessage(IMessageSinkMessage message)
{
var testFailed = message as ITestFailed;
if (testFailed != null)
{
XunitTest test = new XunitTest(testFailed.TestCase as IXunitTestCase, $"[Quarantined] {testFailed.Test.DisplayName}");
SkippedTestCount++;
return innerBus.QueueMessage(new TestSkipped(test, testFailed.Messages.FirstOrDefault()));
}
// Nothing we care about, send it on its way
return innerBus.QueueMessage(message);
}
}
}
namespace MyTests
{
public class TestClass1
{
[CustomFact]
public void SantiCustomTest()
{
Assert.False(true);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment