Skip to content

Commit 9ff9a4c

Browse files
committed
separate typeinfo and testclass interfaces to avoid hack
1 parent 4d98319 commit 9ff9a4c

File tree

10 files changed

+123
-97
lines changed

10 files changed

+123
-97
lines changed

src/SpecFlow.xUnitAdapter.SpecFlowPlugin/Framework/SpecFlowTestDiscoverer.cs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace SpecFlow.xUnitAdapter.SpecFlowPlugin.Framework
1010
public class SpecFlowTestDiscoverer : XunitTestFrameworkDiscoverer
1111
{
1212
public SpecFlowTestDiscoverer(IAssemblyInfo assemblyInfo, ISourceInformationProvider sourceProvider, IMessageSink diagnosticMessageSink, IXunitTestCollectionFactory collectionFactory = null) :
13-
base(CreateSpecFlowProjectAssemblyInfo(assemblyInfo), sourceProvider, diagnosticMessageSink)
13+
base(CreateSpecFlowProjectAssemblyInfo(assemblyInfo), sourceProvider, diagnosticMessageSink, collectionFactory)
1414
{
1515
}
1616

@@ -21,18 +21,21 @@ private static SpecFlowProjectAssemblyInfo CreateSpecFlowProjectAssemblyInfo(IAs
2121
return new SpecFlowProjectAssemblyInfo(assemblyInfo);
2222
}
2323

24-
private bool IsSpecFlowTest(object test)
24+
private bool IsSpecFlowTypeInfo(ITypeInfo typeInfo)
2525
{
26-
return test is SpecFlowFeatureTestClass;
26+
return typeInfo is SpecFlowFeatureTypeInfo;
27+
}
28+
29+
private bool IsSpecFlowTest(ITestClass testClass)
30+
{
31+
return testClass is SpecFlowFeatureTestClass;
2732
}
2833

2934
protected override ITestClass CreateTestClass(ITypeInfo typeInfo)
3035
{
31-
if (IsSpecFlowTest(typeInfo))
36+
if (IsSpecFlowTypeInfo(typeInfo))
3237
{
33-
//TODO: return (ITestClass)new SpecFlowTestClass(this.TestCollectionFactory.Get(typeInfo), typeInfo);
34-
((SpecFlowFeatureTestClass)typeInfo).Hack_SetTestCollection(this.TestCollectionFactory.Get(typeInfo));
35-
return (ITestClass) typeInfo;
38+
return new SpecFlowFeatureTestClass(TestCollectionFactory.Get(typeInfo), typeInfo);
3639
}
3740
return base.CreateTestClass(typeInfo);
3841
}
@@ -43,11 +46,11 @@ protected override bool FindTestsForType(ITestClass testClass, bool includeSourc
4346
if (!IsSpecFlowTest(testClass))
4447
return base.FindTestsForType(testClass, includeSourceInformation, messageBus, discoveryOptions);
4548

46-
var featureTestClass = (SpecFlowFeatureTestClass)testClass;
47-
var gherkinDocument = featureTestClass.GetDocument();
49+
var featureTestClass = ((SpecFlowFeatureTestClass)testClass);
50+
var gherkinDocument = featureTestClass.FeatureTypeInfo.GetDocument();
4851
if (gherkinDocument?.SpecFlowFeature != null)
4952
{
50-
featureTestClass.FeatureName = gherkinDocument.SpecFlowFeature.Name;
53+
featureTestClass.FeatureTypeInfo.FeatureName = gherkinDocument.SpecFlowFeature.Name;
5154
var featureTags = gherkinDocument.SpecFlowFeature.Tags.GetTags().ToArray();
5255
foreach (var scenarioDefinition in gherkinDocument.SpecFlowFeature.ScenarioDefinitions.Where(sd => !(sd is Background)))
5356
{

src/SpecFlow.xUnitAdapter.SpecFlowPlugin/Framework/SpecFlowTestFramework.cs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Xunit.Abstractions;
33
using Xunit.Sdk;
44

5+
// ReSharper disable once CheckNamespace
56
namespace SpecFlow.xUnitAdapter.SpecFlowPlugin
67
{
78
public class SpecFlowTestFramework : XunitTestFramework
@@ -10,14 +11,10 @@ public SpecFlowTestFramework(IMessageSink diagnosticMessageSink) : base(diagnost
1011
{
1112
}
1213

14+
// we only override the discoverer, we can use the built-in executor as it is anyway delegates the actual exectution to the test cases (ScenarioTestCase)
1315
protected override ITestFrameworkDiscoverer CreateDiscoverer(IAssemblyInfo assemblyInfo)
1416
{
1517
return new SpecFlowTestDiscoverer(assemblyInfo, SourceInformationProvider, DiagnosticMessageSink);
1618
}
17-
18-
//protected override ITestFrameworkExecutor CreateExecutor(AssemblyName assemblyName)
19-
//{
20-
// return new SpecFlowTestFrameworkExecutor(assemblyName, SourceInformationProvider, DiagnosticMessageSink);
21-
//}
2219
}
23-
}
20+
}

src/SpecFlow.xUnitAdapter.SpecFlowPlugin/Runners/ScenarioTestCaseRunner.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public void FeatureSetup(GherkinDocument gherkinDocument)
3030
Debug.Assert(gherkinDocument.Feature != null);
3131
var feature = gherkinDocument.Feature;
3232

33-
var assembly = Assembly.LoadFrom(TestCase.FeatureFile.SpecFlowProject.AssemblyPath);
33+
var assembly = Assembly.LoadFrom(TestCase.FeatureTypeInfo.SpecFlowProject.AssemblyPath);
3434
testRunner = TestRunnerManager.GetTestRunner(assembly);
3535
var featureInfo = new FeatureInfo(GetFeatureCulture(feature.Language), feature.Name, feature.Description, ProgrammingLanguage.CSharp, feature.Tags.GetTags().ToArray());
3636
testRunner.OnFeatureStart(featureInfo);
@@ -79,7 +79,7 @@ protected override async Task<RunSummary> RunTestAsync()
7979
var summary = new RunSummary() { Total = 1 };
8080
string output = "";
8181

82-
var gherkinDocument = await this.TestCase.FeatureFile.GetDocumentAsync();
82+
var gherkinDocument = await this.TestCase.FeatureTypeInfo.GetDocumentAsync();
8383

8484

8585
Scenario scenario = null;

src/SpecFlow.xUnitAdapter.SpecFlowPlugin/SpecFlow.xUnitAdapter.SpecFlowPlugin.csproj

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,9 @@
7979
<ItemGroup>
8080
<Compile Include="Runners\XUnitTraceListener.cs" />
8181
<Compile Include="TestArtifacts\SpecFlowFeatureTestClass.cs" />
82-
<Compile Include="TestArtifacts\EmbeddedFeatureFileTestClass.cs" />
83-
<Compile Include="TestArtifacts\FeatureFileTestClass.cs" />
82+
<Compile Include="TestArtifacts\SpecFlowFeatureTypeInfo.cs" />
83+
<Compile Include="TestArtifacts\EmbeddedFeatureTypeInfo.cs" />
84+
<Compile Include="TestArtifacts\FeatureFileTypeInfo.cs" />
8485
<Compile Include="Runners\ScenarioTestCaseRunner.cs" />
8586
<Compile Include="TestArtifacts\SpecFlowGenericFixtureType.cs" />
8687
<Compile Include="SpecFlowParserHelper.cs" />

src/SpecFlow.xUnitAdapter.SpecFlowPlugin/TestArtifacts/EmbeddedFeatureFileTestClass.cs renamed to src/SpecFlow.xUnitAdapter.SpecFlowPlugin/TestArtifacts/EmbeddedFeatureTypeInfo.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,13 @@
55

66
namespace SpecFlow.xUnitAdapter.SpecFlowPlugin.TestArtifacts
77
{
8-
public class EmbeddedFeatureFileTestClass : SpecFlowFeatureTestClass
8+
public class EmbeddedFeatureTypeInfo : SpecFlowFeatureTypeInfo
99
{
10-
public EmbeddedFeatureFileTestClass()
11-
: base()
10+
public EmbeddedFeatureTypeInfo()
1211
{
1312
}
1413

15-
public EmbeddedFeatureFileTestClass(SpecFlowProjectAssemblyInfo specFlowProject, string resourceName)
14+
public EmbeddedFeatureTypeInfo(SpecFlowProjectAssemblyInfo specFlowProject, string resourceName)
1615
: base(specFlowProject, resourceName)
1716
{
1817
}

src/SpecFlow.xUnitAdapter.SpecFlowPlugin/TestArtifacts/FeatureFileTestClass.cs renamed to src/SpecFlow.xUnitAdapter.SpecFlowPlugin/TestArtifacts/FeatureFileTypeInfo.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55

66
namespace SpecFlow.xUnitAdapter.SpecFlowPlugin.TestArtifacts
77
{
8-
public class FeatureFileTestClass : SpecFlowFeatureTestClass
8+
public class FeatureFileTypeInfo : SpecFlowFeatureTypeInfo
99
{
10-
public FeatureFileTestClass()
10+
public FeatureFileTypeInfo()
1111
{
1212
}
1313

14-
public FeatureFileTestClass(SpecFlowProjectAssemblyInfo specFlowProject, string relativePath)
14+
public FeatureFileTypeInfo(SpecFlowProjectAssemblyInfo specFlowProject, string relativePath)
1515
: base(specFlowProject, relativePath)
1616
{
1717
}

src/SpecFlow.xUnitAdapter.SpecFlowPlugin/TestArtifacts/ScenarioTestCase.cs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@ namespace SpecFlow.xUnitAdapter.SpecFlowPlugin.TestArtifacts
1414
{
1515
public class ScenarioTestCase : LongLivedMarshalByRefObject, ITestMethod, IXunitTestCase, IReflectionMethodInfo
1616
{
17-
public SpecFlowFeatureTestClass FeatureFile { get; private set; }
17+
public SpecFlowFeatureTestClass FeatureTestClass { get; private set; }
18+
public SpecFlowFeatureTypeInfo FeatureTypeInfo => FeatureTestClass.FeatureTypeInfo;
1819
public string Name { get; private set; }
1920

2021
public string DisplayName => GetDisplayName();
21-
public string UniqueID => $"{FeatureFile.RelativePath};{Name};{ExampleId}";
22+
public string UniqueID => $"{FeatureTypeInfo.RelativePath};{Name};{ExampleId}";
2223

2324
public ISourceInformation SourceInformation { get; set; }
2425
public string SkipReason { get; set; }
@@ -29,7 +30,7 @@ public class ScenarioTestCase : LongLivedMarshalByRefObject, ITestMethod, IXunit
2930
public bool IsScenarioOutline => !string.IsNullOrEmpty(ExampleId);
3031

3132
object[] ITestCase.TestMethodArguments => ScenarioOutlineParameters?.Cast<object>().ToArray();
32-
public ITestClass TestClass => FeatureFile;
33+
public ITestClass TestClass => FeatureTestClass;
3334
public ITestMethod TestMethod => this;
3435
public IMethodInfo Method => this;
3536

@@ -40,9 +41,9 @@ public ScenarioTestCase()
4041

4142
private ScenarioTestCase(SpecFlowFeatureTestClass featureTestClass, ScenarioDefinition scenario, string[] featureTags, Location location)
4243
{
43-
FeatureFile = featureTestClass;
44+
FeatureTestClass = featureTestClass;
4445
Name = scenario.Name;
45-
SourceInformation = new SourceInformation { FileName = featureTestClass.FeatureFilePath, LineNumber = location?.Line };
46+
SourceInformation = new SourceInformation { FileName = FeatureTypeInfo.FeatureFilePath, LineNumber = location?.Line };
4647
Traits = new Dictionary<string, List<string>>();
4748
Traits.Add("Category", featureTags.Concat(((IHasTags)scenario).Tags.GetTags()).ToList());
4849
}
@@ -70,14 +71,14 @@ private string GetDisplayName()
7071

7172
public void Deserialize(IXunitSerializationInfo data)
7273
{
73-
FeatureFile = data.GetValue<SpecFlowFeatureTestClass>("FeatureFile");
74+
FeatureTestClass = data.GetValue<SpecFlowFeatureTestClass>("FeatureTestClass");
7475
Name = data.GetValue<string>("Name");
7576
ExampleId = data.GetValue<string>("ExampleId");
7677
}
7778

7879
public void Serialize(IXunitSerializationInfo data)
7980
{
80-
data.AddValue("FeatureFile", FeatureFile);
81+
data.AddValue("FeatureTestClass", FeatureTestClass);
8182
data.AddValue("Name", Name);
8283
data.AddValue("ExampleId", ExampleId);
8384
}
Lines changed: 25 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,48 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.IO;
4-
using System.Linq;
5-
using System.Threading.Tasks;
6-
using TechTalk.SpecFlow.Parser;
1+
using System;
72
using Xunit;
83
using Xunit.Abstractions;
9-
using Xunit.Sdk;
104

115
namespace SpecFlow.xUnitAdapter.SpecFlowPlugin.TestArtifacts
126
{
13-
public abstract class SpecFlowFeatureTestClass : LongLivedMarshalByRefObject, ITypeInfo, IReflectionTypeInfo, ITestClass
7+
public class SpecFlowFeatureTestClass : LongLivedMarshalByRefObject, ITestClass
148
{
15-
public string FeatureName { get; set; }
16-
public string RelativePath { get; private set; }
17-
public SpecFlowProjectAssemblyInfo SpecFlowProject { get; private set; }
18-
19-
public virtual string FeatureFilePath { get; protected set; }
20-
21-
IAssemblyInfo ITypeInfo.Assembly => SpecFlowProject;
22-
string ITypeInfo.Name => (FeatureName ?? RelativePath).Replace(".", "");
23-
Type IReflectionTypeInfo.Type { get { return typeof(SpecFlowGenericFixtureType); } }
24-
25-
public ITypeInfo Class => this;
9+
public ITypeInfo Class { get; private set; }
2610
public ITestCollection TestCollection { get; private set; }
2711

28-
#region ITypeInfo default implementation
29-
IEnumerable<IAttributeInfo> ITypeInfo.GetCustomAttributes(string assemblyQualifiedAttributeTypeName) => Enumerable.Empty<IAttributeInfo>();
30-
IEnumerable<ITypeInfo> ITypeInfo.GetGenericArguments() => Enumerable.Empty<ITypeInfo>();
31-
IMethodInfo ITypeInfo.GetMethod(string methodName, bool includePrivateMethod) => null;
32-
IEnumerable<IMethodInfo> ITypeInfo.GetMethods(bool includePrivateMethods) => Enumerable.Empty<IMethodInfo>();
33-
ITypeInfo ITypeInfo.BaseType => null;
34-
IEnumerable<ITypeInfo> ITypeInfo.Interfaces => Enumerable.Empty<ITypeInfo>();
35-
bool ITypeInfo.IsAbstract => false;
36-
bool ITypeInfo.IsGenericParameter => false;
37-
bool ITypeInfo.IsGenericType => false;
38-
bool ITypeInfo.IsSealed => false;
39-
bool ITypeInfo.IsValueType => false;
40-
#endregion
41-
42-
protected SpecFlowFeatureTestClass() { }
12+
public SpecFlowFeatureTypeInfo FeatureTypeInfo => (SpecFlowFeatureTypeInfo)Class;
4313

44-
protected SpecFlowFeatureTestClass(SpecFlowProjectAssemblyInfo specFlowProject, string relativePath)
14+
[Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")]
15+
public SpecFlowFeatureTestClass()
4516
{
46-
SpecFlowProject = specFlowProject;
47-
RelativePath = relativePath;
4817
}
4918

50-
internal void Hack_SetTestCollection(ITestCollection testCollection)
19+
public SpecFlowFeatureTestClass(ITestCollection testCollection, ITypeInfo typeInfo)
5120
{
52-
TestCollection = testCollection;
53-
}
54-
55-
protected ISpecFlowSourceMapper SpecFlowSourceMapper { get; } = new SpecFlowSourceMapperV1();
21+
if (!(typeInfo is SpecFlowFeatureTypeInfo))
22+
throw new ArgumentException($"Must me an instance of {nameof(SpecFlowFeatureTypeInfo)}", "typeInfo");
5623

57-
public virtual void Deserialize(IXunitSerializationInfo data)
58-
{
59-
SpecFlowProject = data.GetValue<SpecFlowProjectAssemblyInfo>("SpecFlowProject");
60-
RelativePath = data.GetValue<string>("RelativePath");
61-
TestCollection = data.GetValue<ITestCollection>("TestCollection");
24+
TestCollection = testCollection;
25+
Class = typeInfo;
6226
}
6327

64-
public virtual void Serialize(IXunitSerializationInfo data)
28+
public void Serialize(IXunitSerializationInfo info)
6529
{
66-
data.AddValue("SpecFlowProject", SpecFlowProject);
67-
data.AddValue("RelativePath", RelativePath);
68-
data.AddValue("TestCollection", TestCollection);
30+
info.AddValue("TestCollection", TestCollection);
31+
info.AddValue("SpecFlowProject", FeatureTypeInfo.SpecFlowProject);
32+
info.AddValue("RelativePath", FeatureTypeInfo.RelativePath);
33+
info.AddValue("TypeInfoKind", Class.GetType().Name);
6934
}
7035

71-
protected SpecFlowDocument ParseDocument(string content, string path, SpecFlowGherkinParser parser)
36+
public void Deserialize(IXunitSerializationInfo info)
7237
{
73-
var sourceMap = this.SpecFlowSourceMapper.ReadSourceMap(content);
74-
75-
this.FeatureFilePath = sourceMap?.SourcePath ?? path;
76-
77-
return parser.Parse(new StringReader(content), this.FeatureFilePath);
38+
TestCollection = info.GetValue<ITestCollection>("TestCollection");
39+
var specFlowProject = info.GetValue<SpecFlowProjectAssemblyInfo>("SpecFlowProject");
40+
var relativePath = info.GetValue<string>("RelativePath");
41+
var typeInfoKind = info.GetValue<string>("TypeInfoKind");
42+
if (typeInfoKind == nameof(FeatureFileTypeInfo))
43+
Class = new FeatureFileTypeInfo(specFlowProject, relativePath);
44+
else if (typeInfoKind == nameof(EmbeddedFeatureTypeInfo))
45+
Class = new EmbeddedFeatureTypeInfo(specFlowProject, relativePath);
7846
}
79-
80-
public abstract SpecFlowDocument GetDocument();
81-
82-
public abstract Task<SpecFlowDocument> GetDocumentAsync();
8347
}
8448
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Threading.Tasks;
6+
using TechTalk.SpecFlow.Parser;
7+
using Xunit;
8+
using Xunit.Abstractions;
9+
10+
namespace SpecFlow.xUnitAdapter.SpecFlowPlugin.TestArtifacts
11+
{
12+
public abstract class SpecFlowFeatureTypeInfo : LongLivedMarshalByRefObject, ITypeInfo, IReflectionTypeInfo
13+
{
14+
public string FeatureName { get; set; }
15+
public string RelativePath { get; }
16+
public SpecFlowProjectAssemblyInfo SpecFlowProject { get; }
17+
18+
public virtual string FeatureFilePath { get; protected set; }
19+
20+
IAssemblyInfo ITypeInfo.Assembly => SpecFlowProject;
21+
string ITypeInfo.Name => (FeatureName ?? RelativePath).Replace(".", "");
22+
Type IReflectionTypeInfo.Type => typeof(SpecFlowGenericFixtureType);
23+
24+
#region ITypeInfo default implementation
25+
IEnumerable<IAttributeInfo> ITypeInfo.GetCustomAttributes(string assemblyQualifiedAttributeTypeName) => Enumerable.Empty<IAttributeInfo>();
26+
IEnumerable<ITypeInfo> ITypeInfo.GetGenericArguments() => Enumerable.Empty<ITypeInfo>();
27+
IMethodInfo ITypeInfo.GetMethod(string methodName, bool includePrivateMethod) => null;
28+
IEnumerable<IMethodInfo> ITypeInfo.GetMethods(bool includePrivateMethods) => Enumerable.Empty<IMethodInfo>();
29+
ITypeInfo ITypeInfo.BaseType => null;
30+
IEnumerable<ITypeInfo> ITypeInfo.Interfaces => Enumerable.Empty<ITypeInfo>();
31+
bool ITypeInfo.IsAbstract => false;
32+
bool ITypeInfo.IsGenericParameter => false;
33+
bool ITypeInfo.IsGenericType => false;
34+
bool ITypeInfo.IsSealed => false;
35+
bool ITypeInfo.IsValueType => false;
36+
#endregion
37+
38+
protected SpecFlowFeatureTypeInfo() { }
39+
40+
protected SpecFlowFeatureTypeInfo(SpecFlowProjectAssemblyInfo specFlowProject, string relativePath)
41+
{
42+
SpecFlowProject = specFlowProject;
43+
RelativePath = relativePath;
44+
}
45+
46+
protected ISpecFlowSourceMapper SpecFlowSourceMapper { get; } = new SpecFlowSourceMapperV1();
47+
48+
protected SpecFlowDocument ParseDocument(string content, string path, SpecFlowGherkinParser parser)
49+
{
50+
var sourceMap = this.SpecFlowSourceMapper.ReadSourceMap(content);
51+
52+
this.FeatureFilePath = sourceMap?.SourcePath ?? path;
53+
54+
return parser.Parse(new StringReader(content), this.FeatureFilePath);
55+
}
56+
57+
public abstract SpecFlowDocument GetDocument();
58+
59+
public abstract Task<SpecFlowDocument> GetDocumentAsync();
60+
}
61+
}

src/SpecFlow.xUnitAdapter.SpecFlowPlugin/TestArtifacts/SpecFlowProjectAssemblyInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,15 @@ public IEnumerable<ITypeInfo> GetTypes(bool includePrivateTypes)
4343
foreach (var resourceName in assembly.GetManifestResourceNames().Where(x => x.EndsWith(".feature")))
4444
{
4545
Console.WriteLine($" {resourceName}");
46-
yield return new EmbeddedFeatureFileTestClass(this, resourceName);
46+
yield return new EmbeddedFeatureTypeInfo(this, resourceName);
4747
}
4848

4949
Console.WriteLine($" Discovering feature files from folder {FeatureFilesFolder}");
5050
foreach (var featureFilePath in Directory.GetFiles(FeatureFilesFolder, "*.feature", SearchOption.AllDirectories))
5151
{
5252
var relativePath = featureFilePath.Substring(FeatureFilesFolder.Length).TrimStart(Path.DirectorySeparatorChar);
5353
Console.WriteLine($" {relativePath}");
54-
yield return new FeatureFileTestClass(this, relativePath);
54+
yield return new FeatureFileTypeInfo(this, relativePath);
5555
}
5656

5757
// discovering "standard" xunit tests to allow incremental transition from the generated style to the new style

0 commit comments

Comments
 (0)