Commit 23ad634a authored by mgravell's avatar mgravell

update dynamic skippable code (from SE.Redis tests)

parent 7ebd9db8
...@@ -68,7 +68,7 @@ public class MySqlServerTestSuite : TestSuite ...@@ -68,7 +68,7 @@ public class MySqlServerTestSuite : TestSuite
public override IDbConnection GetConnection() public override IDbConnection GetConnection()
{ {
if (_skip) throw new SkipTestException("Skipping MySQL Tests - no server."); if (_skip) Skip.Inconclusive("Skipping MySQL Tests - no server.");
return new MySqlConnection(ConnectionString); return new MySqlConnection(ConnectionString);
} }
......
using System; using System;
using Xunit; using Xunit.Sdk;
namespace Dapper.Tests namespace Dapper.Tests
{ {
/// <summary>
/// <para>Override for <see cref="Xunit.FactAttribute"/> that truncates our DisplayName down.</para>
/// <para>
/// Attribute that is applied to a method to indicate that it is a fact that should
/// be run by the test runner. It can also be extended to support a customized definition
/// of a test method.
/// </para>
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
[XunitTestCaseDiscoverer("Dapper.Tests.FactDiscoverer", "Dapper.Tests")]
public class FactAttribute : Xunit.FactAttribute
{
}
/// <summary>
/// <para>Override for <see cref="Xunit.TheoryAttribute"/> that truncates our DisplayName down.</para>
/// <para>
/// Marks a test method as being a data theory. Data theories are tests which are
/// fed various bits of data from a data source, mapping to parameters on the test
/// method. If the data source contains multiple rows, then the test method is executed
/// multiple times (once with each data row). Data is provided by attributes which
/// derive from Xunit.Sdk.DataAttribute (notably, Xunit.InlineDataAttribute and Xunit.MemberDataAttribute).
/// </para>
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
[XunitTestCaseDiscoverer("Dapper.Tests.TheoryDiscoverer", "Dapper.Tests")]
public class TheoryAttribute : Xunit.TheoryAttribute { }
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public sealed class FactLongRunningAttribute : FactAttribute public sealed class FactLongRunningAttribute : FactAttribute
{ {
......
...@@ -9,6 +9,17 @@ ...@@ -9,6 +9,17 @@
namespace Dapper.Tests namespace Dapper.Tests
{ {
public static class Skip
{
public static void Inconclusive(string reason = "inconclusive")
=> throw new SkipTestException(reason);
public static void If<T>(object obj, string reason = null)
where T : class
{
if (obj is T) Skip.Inconclusive(reason ?? $"not valid for {typeof(T).FullName}");
}
}
public class SkipTestException : Exception public class SkipTestException : Exception
{ {
public SkipTestException(string reason) : base(reason) public SkipTestException(string reason) : base(reason)
...@@ -16,31 +27,40 @@ public SkipTestException(string reason) : base(reason) ...@@ -16,31 +27,40 @@ public SkipTestException(string reason) : base(reason)
} }
} }
// Most of the below is a direct copy & port from the wonderful examples by Brad Wilson at public class FactDiscoverer : Xunit.Sdk.FactDiscoverer
// https://github.com/xunit/samples.xunit/tree/master/DynamicSkipExample
public class SkippableFactDiscoverer : IXunitTestCaseDiscoverer
{ {
private readonly IMessageSink _diagnosticMessageSink; public FactDiscoverer(IMessageSink diagnosticMessageSink) : base(diagnosticMessageSink) { }
public SkippableFactDiscoverer(IMessageSink diagnosticMessageSink) protected override IXunitTestCase CreateTestCase(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo factAttribute)
{ => new SkippableTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod);
_diagnosticMessageSink = diagnosticMessageSink; }
}
public IEnumerable<IXunitTestCase> Discover(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo factAttribute) public class TheoryDiscoverer : Xunit.Sdk.TheoryDiscoverer
{ {
yield return new SkippableFactTestCase(_diagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod); public TheoryDiscoverer(IMessageSink diagnosticMessageSink) : base(diagnosticMessageSink) { }
}
protected override IEnumerable<IXunitTestCase> CreateTestCasesForDataRow(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo theoryAttribute, object[] dataRow)
=> new[] { new SkippableTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod, dataRow) };
protected override IEnumerable<IXunitTestCase> CreateTestCasesForSkip(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo theoryAttribute, string skipReason)
=> new[] { new SkippableTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod) };
protected override IEnumerable<IXunitTestCase> CreateTestCasesForTheory(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo theoryAttribute)
=> new[] { new SkippableTheoryTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod) };
protected override IEnumerable<IXunitTestCase> CreateTestCasesForSkippedDataRow(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo theoryAttribute, object[] dataRow, string skipReason)
=> new[] { new NamedSkippedDataRowTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod, skipReason, dataRow) };
} }
public class SkippableFactTestCase : XunitTestCase public class SkippableTestCase : XunitTestCase
{ {
protected override string GetDisplayName(IAttributeInfo factAttribute, string displayName) =>
base.GetDisplayName(factAttribute, displayName).StripName();
[Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")] [Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")]
public SkippableFactTestCase() public SkippableTestCase() { }
{
}
public SkippableFactTestCase(IMessageSink diagnosticMessageSink, TestMethodDisplay defaultMethodDisplay, TestMethodDisplayOptions defaultMethodDisplayOptions, ITestMethod testMethod, object[] testMethodArguments = null) public SkippableTestCase(IMessageSink diagnosticMessageSink, TestMethodDisplay defaultMethodDisplay, TestMethodDisplayOptions defaultMethodDisplayOptions, ITestMethod testMethod, object[] testMethodArguments = null)
: base(diagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testMethod, testMethodArguments) : base(diagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testMethod, testMethodArguments)
{ {
} }
...@@ -52,36 +72,56 @@ public SkippableFactTestCase(IMessageSink diagnosticMessageSink, TestMethodDispl ...@@ -52,36 +72,56 @@ public SkippableFactTestCase(IMessageSink diagnosticMessageSink, TestMethodDispl
ExceptionAggregator aggregator, ExceptionAggregator aggregator,
CancellationTokenSource cancellationTokenSource) CancellationTokenSource cancellationTokenSource)
{ {
var skipMessageBus = new SkippableFactMessageBus(messageBus); var skipMessageBus = new SkippableMessageBus(messageBus);
var result = await base.RunAsync( var result = await base.RunAsync(diagnosticMessageSink, skipMessageBus, constructorArguments, aggregator, cancellationTokenSource).ConfigureAwait(false);
diagnosticMessageSink, return result.Update(skipMessageBus);
skipMessageBus,
constructorArguments,
aggregator,
cancellationTokenSource).ConfigureAwait(false);
if (skipMessageBus.DynamicallySkippedTestCount > 0)
{
result.Failed -= skipMessageBus.DynamicallySkippedTestCount;
result.Skipped += skipMessageBus.DynamicallySkippedTestCount;
}
return result;
} }
} }
public class SkippableFactMessageBus : IMessageBus public class SkippableTheoryTestCase : XunitTheoryTestCase
{ {
private readonly IMessageBus _innerBus; protected override string GetDisplayName(IAttributeInfo factAttribute, string displayName) =>
public SkippableFactMessageBus(IMessageBus innerBus) base.GetDisplayName(factAttribute, displayName).StripName();
[Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")]
public SkippableTheoryTestCase() { }
public SkippableTheoryTestCase(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)
{ {
_innerBus = innerBus; var skipMessageBus = new SkippableMessageBus(messageBus);
var result = await base.RunAsync(diagnosticMessageSink, skipMessageBus, constructorArguments, aggregator, cancellationTokenSource).ConfigureAwait(false);
return result.Update(skipMessageBus);
} }
}
public class NamedSkippedDataRowTestCase : XunitSkippedDataRowTestCase
{
protected override string GetDisplayName(IAttributeInfo factAttribute, string displayName) =>
base.GetDisplayName(factAttribute, displayName).StripName();
[Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")]
public NamedSkippedDataRowTestCase() { }
public NamedSkippedDataRowTestCase(IMessageSink diagnosticMessageSink, TestMethodDisplay defaultMethodDisplay, TestMethodDisplayOptions defaultMethodDisplayOptions, ITestMethod testMethod, string skipReason, object[] testMethodArguments = null)
: base(diagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testMethod, skipReason, testMethodArguments) { }
}
public class SkippableMessageBus : IMessageBus
{
private readonly IMessageBus InnerBus;
public SkippableMessageBus(IMessageBus innerBus) => InnerBus = innerBus;
public int DynamicallySkippedTestCount { get; private set; } public int DynamicallySkippedTestCount { get; private set; }
public void Dispose() public void Dispose() { }
{
}
public bool QueueMessage(IMessageSinkMessage message) public bool QueueMessage(IMessageSinkMessage message)
{ {
...@@ -91,10 +131,26 @@ public bool QueueMessage(IMessageSinkMessage message) ...@@ -91,10 +131,26 @@ public bool QueueMessage(IMessageSinkMessage message)
if (exceptionType == typeof(SkipTestException).FullName) if (exceptionType == typeof(SkipTestException).FullName)
{ {
DynamicallySkippedTestCount++; DynamicallySkippedTestCount++;
return _innerBus.QueueMessage(new TestSkipped(testFailed.Test, testFailed.Messages.FirstOrDefault())); return InnerBus.QueueMessage(new TestSkipped(testFailed.Test, testFailed.Messages.FirstOrDefault()));
} }
} }
return _innerBus.QueueMessage(message); return InnerBus.QueueMessage(message);
}
}
internal static class XUnitExtensions
{
internal static string StripName(this string name) =>
name.Replace("Dapper.Tests.", "");
public static RunSummary Update(this RunSummary summary, SkippableMessageBus bus)
{
if (bus.DynamicallySkippedTestCount > 0)
{
summary.Failed -= bus.DynamicallySkippedTestCount;
summary.Skipped += bus.DynamicallySkippedTestCount;
}
return summary;
} }
} }
} }
...@@ -718,11 +718,7 @@ private class HazSqlGeo ...@@ -718,11 +718,7 @@ private class HazSqlGeo
[Fact] [Fact]
public void DBGeography_SO24405645_SO24402424() public void DBGeography_SO24405645_SO24402424()
{ {
try SkipIfMsDataClient();
{
SkipIfMsDataClient();
}
catch (SkipTestException) { return; } // just while we figure out why that isn't skipping
EntityFramework.Handlers.Register(); EntityFramework.Handlers.Register();
...@@ -745,11 +741,7 @@ public void DBGeography_SO24405645_SO24402424() ...@@ -745,11 +741,7 @@ public void DBGeography_SO24405645_SO24402424()
[Fact] [Fact]
public void SqlGeography_SO25538154() public void SqlGeography_SO25538154()
{ {
try SkipIfMsDataClient();
{
SkipIfMsDataClient();
}
catch (SkipTestException) { return; } // just while we figure out why that isn't skipping
SqlMapper.ResetTypeHandlers(); SqlMapper.ResetTypeHandlers();
connection.Execute("create table #SqlGeo (id int, geo geography, geometry geometry)"); connection.Execute("create table #SqlGeo (id int, geo geography, geometry geometry)");
...@@ -789,11 +781,7 @@ public void NullableSqlGeometry() ...@@ -789,11 +781,7 @@ public void NullableSqlGeometry()
[Fact] [Fact]
public void SqlHierarchyId_SO18888911() public void SqlHierarchyId_SO18888911()
{ {
try SkipIfMsDataClient();
{
SkipIfMsDataClient();
}
catch (SkipTestException) { return; } // just while we figure out why that isn't skipping
SqlMapper.ResetTypeHandlers(); SqlMapper.ResetTypeHandlers();
var row = connection.Query<HazSqlHierarchy>("select 3 as [Id], hierarchyid::Parse('/1/2/3/') as [Path]").Single(); var row = connection.Query<HazSqlHierarchy>("select 3 as [Id], hierarchyid::Parse('/1/2/3/') as [Path]").Single();
......
...@@ -22,11 +22,7 @@ public EntityFrameworkTests() ...@@ -22,11 +22,7 @@ public EntityFrameworkTests()
[Fact] [Fact]
public void Issue570_DbGeo_HasValues() public void Issue570_DbGeo_HasValues()
{ {
try SkipIfMsDataClient();
{
SkipIfMsDataClient();
}
catch (SkipTestException) { return; } // just while we figure out why that isn't skipping
EntityFramework.Handlers.Register(); EntityFramework.Handlers.Register();
const string redmond = "POINT (-122.1215 47.6740)"; const string redmond = "POINT (-122.1215 47.6740)";
...@@ -43,11 +39,7 @@ public void Issue570_DbGeo_HasValues() ...@@ -43,11 +39,7 @@ public void Issue570_DbGeo_HasValues()
[Fact] [Fact]
public void Issue22_ExecuteScalar_EntityFramework() public void Issue22_ExecuteScalar_EntityFramework()
{ {
try SkipIfMsDataClient();
{
SkipIfMsDataClient();
}
catch (SkipTestException) { return; } // just while we figure out why that isn't skipping
var geo = DbGeography.LineFromText("LINESTRING(-122.360 47.656, -122.343 47.656 )", 4326); var geo = DbGeography.LineFromText("LINESTRING(-122.360 47.656, -122.343 47.656 )", 4326);
var geo2 = connection.ExecuteScalar<DbGeography>("select @geo", new { geo }); var geo2 = connection.ExecuteScalar<DbGeography>("select @geo", new { geo });
......
...@@ -82,10 +82,7 @@ public sealed class MicrosoftSqlClientProvider : SqlServerDatabaseProvider ...@@ -82,10 +82,7 @@ public sealed class MicrosoftSqlClientProvider : SqlServerDatabaseProvider
public abstract class TestBase<TProvider> : IDisposable where TProvider : DatabaseProvider public abstract class TestBase<TProvider> : IDisposable where TProvider : DatabaseProvider
{ {
protected void SkipIfMsDataClient() protected void SkipIfMsDataClient()
{ => Skip.If<Microsoft.Data.SqlClient.SqlConnection>(connection);
if (connection is Microsoft.Data.SqlClient.SqlConnection)
throw new SkipTestException("Not supported on Microsoft.Data.SqlClient");
}
protected DbConnection GetOpenConnection() => Provider.GetOpenConnection(); protected DbConnection GetOpenConnection() => Provider.GetOpenConnection();
protected DbConnection GetClosedConnection() => Provider.GetClosedConnection(); protected DbConnection GetClosedConnection() => Provider.GetClosedConnection();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment