Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PoC for xUnit handling of @Ignore tag on a feature #968

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ public override void SetTestClassParallelize(TestClassGenerationContext generati

public override void FinalizeTestClass(TestClassGenerationContext generationContext)
{
base.FinalizeTestClass(generationContext);
IgnoreFeature(generationContext);

// testRunner.ScenarioContext.ScenarioContainer.RegisterInstanceAs<ITestOutputHelper>(_testOutputHelper);
generationContext.ScenarioInitializeMethod.Statements.Add(
Expand All @@ -134,5 +134,10 @@ public override void FinalizeTestClass(TestClassGenerationContext generationCont
new CodeTypeReference(OUTPUT_INTERFACE)),
new CodeVariableReferenceExpression(OUTPUT_INTERFACE_FIELD_NAME)));
}

protected override bool IsTestMethodAlreadyIgnored(CodeMemberMethod testMethod)
{
return IsTestMethodAlreadyIgnored(testMethod, FACT_ATTRIBUTE, THEORY_ATTRIBUTE);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public class XUnitTestGeneratorProvider : IUnitTestGeneratorProvider
private const string TRAIT_ATTRIBUTE = "Xunit.TraitAttribute";
private const string IUSEFIXTURE_INTERFACE = "Xunit.IUseFixture";
private const string CATEGORY_PROPERTY_NAME = "Category";
private const string IGNORE_TAG = "@Ignore";

private CodeTypeDeclaration _currentFixtureDataTypeDeclaration = null;

Expand Down Expand Up @@ -177,7 +178,9 @@ public void SetTestCleanupMethod(TestClassGenerationContext generationContext)

public void SetTestClassIgnore(TestClassGenerationContext generationContext)
{
//TODO: how to do class level ignore?
// The individual tests have to get Skip argument in their attributes
// xUnit does not provide a way to Skip a set of tests - https://xunit.github.io/docs/comparisons.html#attributes
// This is handled in FinalizeTestClass
}

public virtual void SetTestMethodIgnore(TestClassGenerationContext generationContext, CodeMemberMethod testMethod)
Expand Down Expand Up @@ -242,7 +245,51 @@ protected virtual CodeTypeReference CreateFixtureInterface(TestClassGenerationCo

public virtual void FinalizeTestClass(TestClassGenerationContext generationContext)
{
// by default, doing nothing to the final generated code
IgnoreFeature(generationContext);
}

protected virtual void IgnoreFeature(TestClassGenerationContext generationContext)
{
var featureHasIgnoreTag = generationContext.Feature.Tags
.Any(x => string.Equals(x.Name, IGNORE_TAG, StringComparison.InvariantCultureIgnoreCase));

if (featureHasIgnoreTag)
{
foreach (CodeTypeMember member in generationContext.TestClass.Members)
{
var method = member as CodeMemberMethod;
if (method != null && !IsTestMethodAlreadyIgnored(method))
{
SetTestMethodIgnore(generationContext, method);
}
}
}
}

protected virtual bool IsTestMethodAlreadyIgnored(CodeMemberMethod testMethod)
{
return IsTestMethodAlreadyIgnored(testMethod, FACT_ATTRIBUTE, THEORY_ATTRIBUTE);
}

protected static bool IsTestMethodAlreadyIgnored(CodeMemberMethod testMethod, string factAttributeName, string theoryAttributeName)
{
var factAttr = testMethod.CustomAttributes.OfType<CodeAttributeDeclaration>()
.FirstOrDefault(codeAttributeDeclaration => codeAttributeDeclaration.Name == factAttributeName);

var hasIgnoredFact = factAttr?.Arguments.OfType<CodeAttributeArgument>()
.Any(x =>
string.Equals(x.Name, FACT_ATTRIBUTE_SKIP_PROPERTY_NAME, StringComparison.InvariantCultureIgnoreCase));

var theoryAttr = testMethod.CustomAttributes.OfType<CodeAttributeDeclaration>()
.FirstOrDefault(codeAttributeDeclaration => codeAttributeDeclaration.Name == theoryAttributeName);

var hasIgnoredTheory = theoryAttr?.Arguments.OfType<CodeAttributeArgument>()
.Any(x =>
string.Equals(x.Name, THEORY_ATTRIBUTE_SKIP_PROPERTY_NAME, StringComparison.InvariantCultureIgnoreCase));

var result = hasIgnoredFact.GetValueOrDefault() || hasIgnoredTheory.GetValueOrDefault();

return result;
}

public void SetTestMethodAsRow(TestClassGenerationContext generationContext, CodeMemberMethod testMethod, string scenarioTitle, string exampleSetName, string variantName, IEnumerable<KeyValuePair<string, string>> arguments)
Expand Down
90 changes: 90 additions & 0 deletions Tests/TechTalk.SpecFlow.Specs/Features/XUnit2Provider.feature
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,96 @@ Examples:
| Succeeded |
| 0 |

Scenario: Should be able to ignore a scenario
Given there is a SpecFlow project
And the project is configured to use the xUnit provider
And there is a feature file in the project as
"""
Feature: Simple Feature

Scenario: First
Given there is something
Then something should happen

@ignore
Scenario: Second
Given there is something
Then something should happen
"""
And all steps are bound and pass
When I execute the tests with xUnit
Then the execution summary should contain
| Succeeded | Ignored |
| 1 | 1 |

Scenario: Should be able to ignore all Scenarios in a feature
Given there is a SpecFlow project
And the project is configured to use the xUnit provider
And there is a feature file in the project as
"""
@ignore
Feature: Simple Feature

Scenario: First
Given there is something
Then something should happen

@ignore
Scenario: Second
Given there is something
Then something should happen

Scenario: Third
Given there is something else
Then something else should happen
"""
And all steps are bound and pass
When I execute the tests with xUnit
Then the execution summary should contain
| Succeeded | Ignored |
| 0 | 3 |

Scenario: Should be able to ignore all Scenarios and Scenario Outlines in a feature
Given there is a SpecFlow project
And the project is configured to use the xUnit provider
And there is a feature file in the project as
"""
@ignore
Feature: Simple Feature

Scenario: First
Given there is something
Then something should happen

Scenario Outline: First Outline
Given there is something
When I do <what>
Then something should happen
Examples:
| what |
| something |
| something else |

@ignore
Scenario Outline: Second Outline
Given there is something
When I do <what>
Then something should happen
Examples:
| what |
| something |
| something else |

Scenario: Last
Given there is something
Then something should happen
"""
And all steps are bound and pass
When I execute the tests with xUnit
Then the execution summary should contain
| Succeeded | Ignored |
| 0 | 4 |

Scenario Outline: Should handle scenario outlines
Given there is a SpecFlow project
And the project is configured to use the xUnit provider
Expand Down
90 changes: 90 additions & 0 deletions Tests/TechTalk.SpecFlow.Specs/Features/XUnitProvider.feature
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,96 @@ Examples:
| Succeeded |
| 0 |

Scenario: Should be able to ignore a scenario
Given there is a SpecFlow project
And the project is configured to use the xUnit.1 provider
And there is a feature file in the project as
"""
Feature: Simple Feature

Scenario: First
Given there is something
Then something should happen

@ignore
Scenario: Second
Given there is something
Then something should happen
"""
And all steps are bound and pass
When I execute the tests with xUnit
Then the execution summary should contain
| Succeeded | Ignored |
| 1 | 1 |

Scenario: Should be able to ignore all Scenarios in a feature
Given there is a SpecFlow project
And the project is configured to use the xUnit.1 provider
And there is a feature file in the project as
"""
@ignore
Feature: Simple Feature

Scenario: First
Given there is something
Then something should happen

@ignore
Scenario: Second
Given there is something
Then something should happen

Scenario: Third
Given there is something else
Then something else should happen
"""
And all steps are bound and pass
When I execute the tests with xUnit
Then the execution summary should contain
| Succeeded | Ignored |
| 0 | 3 |

Scenario: Should be able to ignore all Scenarios and Scenario Outlines in a feature
Given there is a SpecFlow project
And the project is configured to use the xUnit.1 provider
And there is a feature file in the project as
"""
@ignore
Feature: Simple Feature

Scenario: First
Given there is something
Then something should happen

Scenario Outline: First Outline
Given there is something
When I do <what>
Then something should happen
Examples:
| what |
| something |
| something else |

@ignore
Scenario Outline: Second Outline
Given there is something
When I do <what>
Then something should happen
Examples:
| what |
| something |
| something else |

Scenario: Last
Given there is something
Then something should happen
"""
And all steps are bound and pass
When I execute the tests with xUnit
Then the execution summary should contain
| Succeeded | Ignored |
| 0 | 4 |

Scenario Outline: Should handle scenario outlines
Given there is a SpecFlow project
And the project is configured to use the xUnit.1 provider
Expand Down