Skip to content

Commit

Permalink
Add custom Xunit runner to allow skipping tests after they have alrea…
Browse files Browse the repository at this point in the history
…dy failed, if the failure is expected (because of missing support in Jet).
  • Loading branch information
lauxjpn committed Oct 13, 2023
1 parent ca8472c commit 5459956
Show file tree
Hide file tree
Showing 14 changed files with 544 additions and 51 deletions.
3 changes: 2 additions & 1 deletion test/EFCore.Jet.FunctionalTests/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@

[assembly: CollectionBehavior(DisableTestParallelization = true)]
[assembly: TestCollectionOrderer("EntityFrameworkCore.Jet.FunctionalTests.TestUtilities.Xunit." + nameof(AscendingTestCollectionOrderer), "EntityFrameworkCore.Jet.FunctionalTests")]
[assembly: TestCaseOrderer("EntityFrameworkCore.Jet.FunctionalTests.TestUtilities.Xunit." + nameof(AscendingTestCaseOrderer), "EntityFrameworkCore.Jet.FunctionalTests")]
[assembly: TestCaseOrderer("EntityFrameworkCore.Jet.FunctionalTests.TestUtilities.Xunit." + nameof(AscendingTestCaseOrderer), "EntityFrameworkCore.Jet.FunctionalTests")]
[assembly: TestFramework("EntityFrameworkCore.Jet.FunctionalTests.TestUtilities.Xunit.JetXunitTestFramework", "EntityFrameworkCore.Jet.FunctionalTests")]
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@
using Xunit.Sdk;

// ReSharper disable once CheckNamespace
namespace EntityFrameworkCore.Jet.FunctionalTests.TestUtilities.Xunit
namespace EntityFrameworkCore.Jet.FunctionalTests.TestUtilities.Xunit;

public class AscendingTestCaseOrderer : ITestCaseOrderer
{
public class AscendingTestCaseOrderer : ITestCaseOrderer
{
public IEnumerable<TTestCase> OrderTestCases<TTestCase>(IEnumerable<TTestCase> testCases)
where TTestCase : ITestCase
=> testCases.OrderBy(c => c.DisplayName, StringComparer.OrdinalIgnoreCase);
}
public IEnumerable<TTestCase> OrderTestCases<TTestCase>(IEnumerable<TTestCase> testCases)
where TTestCase : ITestCase
=> testCases.OrderBy(c => c.DisplayName, StringComparer.OrdinalIgnoreCase);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@
using Xunit.Abstractions;

// ReSharper disable once CheckNamespace
namespace EntityFrameworkCore.Jet.FunctionalTests.TestUtilities.Xunit
namespace EntityFrameworkCore.Jet.FunctionalTests.TestUtilities.Xunit;

public class AscendingTestCollectionOrderer : ITestCollectionOrderer
{
public class AscendingTestCollectionOrderer : ITestCollectionOrderer
{
public IEnumerable<ITestCollection> OrderTestCollections(IEnumerable<ITestCollection> testCollections)
=> testCollections.OrderBy(c => c.DisplayName, StringComparer.OrdinalIgnoreCase);
}
public IEnumerable<ITestCollection> OrderTestCollections(IEnumerable<ITestCollection> testCollections)
=> testCollections.OrderBy(c => c.DisplayName, StringComparer.OrdinalIgnoreCase);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,33 @@
using Xunit.Sdk;

// ReSharper disable once CheckNamespace
namespace EntityFrameworkCore.Jet.FunctionalTests.TestUtilities.Xunit
namespace EntityFrameworkCore.Jet.FunctionalTests.TestUtilities.Xunit;

public class ExceptionTestCaseOrderer : ITestCaseOrderer
{
public class ExceptionTestCaseOrderer : ITestCaseOrderer
private readonly string[] _testCaseOrder =
{
private readonly string[] _testCaseOrder =
{
"Select_GetValueOrDefault_on_DateTime",
"Select_byte_constant",
"Select_DTO_with_member_init_distinct_in_subquery_translated_to_server",
"Select_Except_reference_projection",
"Select_Union",
"Select_DTO_with_member_init_distinct_in_subquery_translated_to_server_2",
"Select_bool_closure",
};
"Select_GetValueOrDefault_on_DateTime",
"Select_byte_constant",
"Select_DTO_with_member_init_distinct_in_subquery_translated_to_server",
"Select_Except_reference_projection",
"Select_Union",
"Select_DTO_with_member_init_distinct_in_subquery_translated_to_server_2",
"Select_bool_closure",
};

public IEnumerable<TTestCase> OrderTestCases<TTestCase>(IEnumerable<TTestCase> testCases)
where TTestCase : ITestCase
{
var orderedTestCases = testCases.OrderBy(c => Array.IndexOf(_testCaseOrder, c.TestMethod.Method.Name)).ToList();
public IEnumerable<TTestCase> OrderTestCases<TTestCase>(IEnumerable<TTestCase> testCases)
where TTestCase : ITestCase
{
var orderedTestCases = testCases.OrderBy(c => Array.IndexOf(_testCaseOrder, c.TestMethod.Method.Name)).ToList();

var builder = new StringBuilder()
.AppendLine("Test Case Order:")
.AppendLine(string.Join(Environment.NewLine, orderedTestCases.Select(c => c.TestMethod.Method.Name)));
var builder = new StringBuilder()
.AppendLine("Test Case Order:")
.AppendLine(string.Join(Environment.NewLine, orderedTestCases.Select(c => c.TestMethod.Method.Name)));

Debug.WriteLine(builder);
Console.WriteLine(builder);
Debug.WriteLine(builder);
Console.WriteLine(builder);

return orderedTestCases;
}
return orderedTestCases;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Microsoft.EntityFrameworkCore.TestUtilities.Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;

namespace EntityFrameworkCore.Jet.FunctionalTests.TestUtilities.Xunit;

public class JetConditionalFactDiscoverer : ConditionalFactDiscoverer
{
public JetConditionalFactDiscoverer(IMessageSink messageSink)
: base(messageSink)
{
}

protected override IXunitTestCase CreateTestCase(
ITestFrameworkDiscoveryOptions discoveryOptions,
ITestMethod testMethod,
IAttributeInfo factAttribute)
=> new JetConditionalFactTestCase(
DiagnosticMessageSink,
discoveryOptions.MethodDisplayOrDefault(),
discoveryOptions.MethodDisplayOptionsOrDefault(),
testMethod);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore.TestUtilities.Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;

namespace EntityFrameworkCore.Jet.FunctionalTests.TestUtilities.Xunit;

/// <remarks>
/// We cannot inherit from ConditionalFactTestCase, because it's sealed.
/// </remarks>
public sealed class JetConditionalFactTestCase : XunitTestCase
{
[Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")]
public JetConditionalFactTestCase()
{
}

public JetConditionalFactTestCase(
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)
=> await XunitTestCaseExtensions.TrySkipAsync(this, messageBus)
? new RunSummary { Total = 1, Skipped = 1 }
: await new JetXunitTestCaseRunner(
this,
DisplayName,
SkipReason,
constructorArguments,
TestMethodArguments,
messageBus,
aggregator,
cancellationTokenSource).RunAsync();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.TestUtilities.Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;

namespace EntityFrameworkCore.Jet.FunctionalTests.TestUtilities.Xunit;

public class JetConditionalTheoryDiscoverer : ConditionalTheoryDiscoverer
{
public JetConditionalTheoryDiscoverer(IMessageSink messageSink)
: base(messageSink)
{
}

protected override IEnumerable<IXunitTestCase> CreateTestCasesForTheory(
ITestFrameworkDiscoveryOptions discoveryOptions,
ITestMethod testMethod,
IAttributeInfo theoryAttribute)
{
yield return new JetConditionalTheoryTestCase(
DiagnosticMessageSink,
discoveryOptions.MethodDisplayOrDefault(),
discoveryOptions.MethodDisplayOptionsOrDefault(),
testMethod);
}

protected override IEnumerable<IXunitTestCase> CreateTestCasesForDataRow(
ITestFrameworkDiscoveryOptions discoveryOptions,
ITestMethod testMethod,
IAttributeInfo theoryAttribute,
object[] dataRow)
{
yield return new JetConditionalFactTestCase(
DiagnosticMessageSink,
discoveryOptions.MethodDisplayOrDefault(),
discoveryOptions.MethodDisplayOptionsOrDefault(),
testMethod,
dataRow);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore.TestUtilities.Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;

namespace EntityFrameworkCore.Jet.FunctionalTests.TestUtilities.Xunit;

/// <remarks>
/// We cannot inherit from ConditionalTheoryTestCase, because it's sealed.
/// </remarks>
public sealed class JetConditionalTheoryTestCase : XunitTheoryTestCase
{
[Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")]
public JetConditionalTheoryTestCase()
{
}

public JetConditionalTheoryTestCase(
IMessageSink diagnosticMessageSink,
TestMethodDisplay defaultMethodDisplay,
TestMethodDisplayOptions defaultMethodDisplayOptions,
ITestMethod testMethod)
: base(diagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testMethod)
{
}

public override async Task<RunSummary> RunAsync(
IMessageSink diagnosticMessageSink,
IMessageBus messageBus,
object[] constructorArguments,
ExceptionAggregator aggregator,
CancellationTokenSource cancellationTokenSource)
=> await XunitTestCaseExtensions.TrySkipAsync(this, messageBus)
? new RunSummary { Total = 1, Skipped = 1 }
: await new JetXunitTheoryTestCaseRunner(
this,
DisplayName,
SkipReason,
constructorArguments,
diagnosticMessageSink,
messageBus,
aggregator,
cancellationTokenSource)
.RunAsync();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Xunit.Abstractions;
using Xunit.Sdk;

namespace EntityFrameworkCore.Jet.FunctionalTests.TestUtilities.Xunit;

public class JetXunitTestCaseRunner : XunitTestCaseRunner
{
public JetXunitTestCaseRunner(
IXunitTestCase testCase,
string displayName,
string skipReason,
object[] constructorArguments,
object[] testMethodArguments,
IMessageBus messageBus,
ExceptionAggregator aggregator,
CancellationTokenSource cancellationTokenSource)
: base(
testCase,
displayName,
skipReason,
constructorArguments,
testMethodArguments,
messageBus,
aggregator,
cancellationTokenSource)
{
}

protected override XunitTestRunner CreateTestRunner(
ITest test,
IMessageBus messageBus,
Type testClass,
object[] constructorArguments,
MethodInfo testMethod,
object[] testMethodArguments,
string skipReason,
IReadOnlyList<BeforeAfterTestAttribute> beforeAfterAttributes,
ExceptionAggregator aggregator,
CancellationTokenSource cancellationTokenSource)
=> new JetXunitTestRunner(
test,
messageBus,
testClass,
constructorArguments,
testMethod,
testMethodArguments,
skipReason,
beforeAfterAttributes,
new ExceptionAggregator(aggregator),
cancellationTokenSource);

/// <remarks>
/// `TestRunner&lt;TTestCase&gt;.RunAsync()` is not virtual, so we need to override this method here to call our own
/// `JetXunitTestRunner.RunAsync()` implementation.
/// </remarks>>
protected override Task<RunSummary> RunTestAsync()
=> ((JetXunitTestRunner)CreateTestRunner(
CreateTest(TestCase, DisplayName),
MessageBus,
TestClass,
ConstructorArguments,
TestMethod,
TestMethodArguments,
SkipReason,
BeforeAfterAttributes,
Aggregator,
CancellationTokenSource))
.RunAsync();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Xunit.Abstractions;
using Xunit.Sdk;

namespace EntityFrameworkCore.Jet.FunctionalTests.TestUtilities.Xunit;

public class JetXunitTestFramework : XunitTestFramework
{
public JetXunitTestFramework(IMessageSink messageSink) : base(messageSink)
{
}

protected override ITestFrameworkDiscoverer CreateDiscoverer(IAssemblyInfo assemblyInfo)
=> new JetXunitTestFrameworkDiscoverer(assemblyInfo, SourceInformationProvider, DiagnosticMessageSink);
}
Loading

0 comments on commit 5459956

Please sign in to comment.