Skip to content

Commit

Permalink
Fix step definition attribute support for the Visual Studio Extension (
Browse files Browse the repository at this point in the history
…#2065)

* Fix step definition attribute support for the Visual Studio Extension

* changelog
  • Loading branch information
tzongithub committed Jul 23, 2020
1 parent 1e60a95 commit 2324c4b
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 2 deletions.
23 changes: 22 additions & 1 deletion TechTalk.SpecFlow/Bindings/Discovery/BindingSourceProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,16 @@ private bool IsBindingType(BindingSourceType bindingSourceType)

private bool IsStepDefinitionAttribute(BindingSourceAttribute attribute)
{
return typeof(StepDefinitionBaseAttribute).IsAssignableFrom(attribute.AttributeType);
//NOTE: the IsAssignableFrom calls below are not the built-in ones from the Type system but custom extension methods.
//The IBindingType based IsAssignableFrom does not support polymorphism if the IBindingType is not IPolymorphicBindingType (e.g. RuntimeBindingType)
//The Visual Studio Extension uses a source code based IBindingType that cannot support IPolymorphicBindingType.
//Please do not remove the checks for the sub-classes.
return
typeof(GivenAttribute).IsAssignableFrom(attribute.AttributeType) ||
typeof(WhenAttribute).IsAssignableFrom(attribute.AttributeType) ||
typeof(ThenAttribute).IsAssignableFrom(attribute.AttributeType) ||
typeof(StepDefinitionAttribute).IsAssignableFrom(attribute.AttributeType) ||
typeof(StepDefinitionBaseAttribute).IsAssignableFrom(attribute.AttributeType);
}

private bool IsHookAttribute(BindingSourceAttribute attribute)
Expand Down Expand Up @@ -297,6 +306,18 @@ protected virtual bool ValidateStepArgumentTransformation(BindingSourceMethod bi

private IEnumerable<StepDefinitionType> GetStepDefinitionTypes(BindingSourceAttribute stepDefinitionAttribute)
{
//Note: the Visual Studio Extension resolves the BindingSourceAttribute from the step definition source code without the Types property.
//The Types property is only available at runtime when a StepDefinitionBaseAttribute can be reflected.
//Please do not remove the checks for the sub-classes.
if (typeof(GivenAttribute).IsAssignableFrom(stepDefinitionAttribute.AttributeType))
return new[] { StepDefinitionType.Given };
if (typeof(WhenAttribute).IsAssignableFrom(stepDefinitionAttribute.AttributeType))
return new[] { StepDefinitionType.When };
if (typeof(ThenAttribute).IsAssignableFrom(stepDefinitionAttribute.AttributeType))
return new[] { StepDefinitionType.Then };
if (typeof(StepDefinitionAttribute).IsAssignableFrom(stepDefinitionAttribute.AttributeType))
return new[] { StepDefinitionType.Given, StepDefinitionType.When, StepDefinitionType.Then };

return stepDefinitionAttribute.NamedAttributeValues["Types"].GetValue<IEnumerable<StepDefinitionType>>();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using TechTalk.SpecFlow.Bindings;
using TechTalk.SpecFlow.Bindings.Discovery;
using TechTalk.SpecFlow.Bindings.Reflection;
using Xunit;

namespace TechTalk.SpecFlow.RuntimeTests.Bindings.Discovery
{
public class BindingSourceProcessorTests
{
[Fact]
public void ProcessTypeAndMethod_InVisualStudioExtension_ShouldFindBinding()
{
// The Visual Studio Extension uses a source code based binding reflection that
// * cannot support IPolymorphicBindingType
// * resolves the BindingSourceAttribute from the step definition source code without the Types property

//ARRANGE
var sut = CreateBindingSourceProcessor();

BindingSourceType bindingSourceType = new BindingSourceType
{

Attributes = new[]
{
CreateBindingSourceAttribute("BindingAttribute", "TechTalk.SpecFlow.BindingAttribute")
},
};

BindingSourceMethod bindingSourceMethod = new BindingSourceMethod();
bindingSourceMethod.Attributes = new[]
{
CreateBindingSourceAttribute("GivenAttribute", "TechTalk.SpecFlow.GivenAttribute")
.WithValue("an authenticated user"),
};

//ACT
sut.ProcessType(bindingSourceType);
sut.ProcessMethod(bindingSourceMethod);

//ASSERT
var binding = sut.StepDefinitionBindings.Should().ContainSingle().Subject;
binding.StepDefinitionType.Should().Be(StepDefinitionType.Given);
binding.Regex.Should().NotBeNull();
binding.Regex.IsMatch("an authenticated user").Should().BeTrue();
}

private static BindingSourceAttribute CreateBindingSourceAttribute(string name, string fullName) => new BindingSourceAttribute
{
AttributeType = new BindingType(name, fullName, "default"),
AttributeValues = new IBindingSourceAttributeValueProvider[0],
NamedAttributeValues = new Dictionary<string, IBindingSourceAttributeValueProvider>()
};

private BindingSourceProcessorStub CreateBindingSourceProcessor()
{
//NOTE: BindingSourceProcessor is abstract, to test its base functionality we need to instantiate a subclass
return new BindingSourceProcessorStub();
}
}

public static class BindingSourceTestExtensions
{
public static BindingSourceAttribute WithValue(this BindingSourceAttribute a, string val)
{
var values = a.AttributeValues == null ? new List<IBindingSourceAttributeValueProvider>() : a.AttributeValues.ToList();

values.Add(new BindingSourceAttributeValueProvider(val));

a.AttributeValues = values.ToArray();
return a;
}
}
}
5 changes: 4 additions & 1 deletion changelog.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
Changes after 3.3.57

Fixes:
+ Fix step definition attribute support for the Visual Studio Extension #2065

Changes:
+ Add a new `TestRunEnd` extension point for plugins

Changes after 3.3.30
3.3.57

Changes:
+ Add `SpecFlow.Tools.MSBuild.Generation` as a dependency to the `SpecFlow.xUnit`, `SpecFlow.MSTest`, `SpecFlow.NUnit` packages
Expand Down

0 comments on commit 2324c4b

Please sign in to comment.