Skip to content

Commit

Permalink
Hook with multiple Tags scoped are executed more than once (#848)
Browse files Browse the repository at this point in the history
* add failing tests
* Fix for #848 Hook with multiple Tags scoped are executed more than once

* making sure that the ordering is preserved (the GroupBy might change the order)
  • Loading branch information
SabotageAndi committed May 18, 2017
1 parent 0d7e80f commit 32b6938
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 12 deletions.
26 changes: 14 additions & 12 deletions TechTalk.SpecFlow/Infrastructure/TestExecutionEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -208,17 +208,24 @@ protected virtual void FireScenarioEvents(HookType bindingEvent)
FireEvents(bindingEvent);
}

private void FireEvents(HookType bindingEvent)
private void FireEvents(HookType hookType)
{
var stepContext = contextManager.GetStepContext();

foreach (IHookBinding eventBinding in GetOrderedHooks(bindingEvent))
int scopeMatches;
var matchingHooks = bindingRegistry.GetHooks(hookType)
.Where(hookBinding => !hookBinding.IsScoped ||
hookBinding.BindingScope.Match(stepContext, out scopeMatches));

//HACK: The InvokeHook requires an IHookBinding that contains the scope as well
// if multiple scopes mathching for the same method, we take the first one.
// The InvokeHook uses only the Method anyway...
// The only problem could be if the same method is decorated with hook attributes using different order,
// but in this case it is anyway impossible to tell the right ordering.
var uniqueMatchingHooks = matchingHooks.GroupBy(hookBinding => hookBinding.Method).Select(g => g.First());
foreach (var hookBinding in uniqueMatchingHooks.OrderBy(x => x.HookOrder))
{
int scopeMatches;
if (eventBinding.IsScoped && !eventBinding.BindingScope.Match(stepContext, out scopeMatches))
continue;

InvokeHook(bindingInvoker, eventBinding, bindingEvent);
InvokeHook(bindingInvoker, hookBinding, hookType);
}
}

Expand Down Expand Up @@ -272,11 +279,6 @@ private object ResolveArgument(IObjectContainer container, IBindingParameter par
return testObjectResolver.ResolveBindingInstance(runtimeParameterType.Type, container);
}

private IOrderedEnumerable<IHookBinding> GetOrderedHooks(HookType bindingEvent)
{
return bindingRegistry.GetHooks(bindingEvent).OrderBy(x => x.HookOrder);
}

private void ExecuteStep(IContextManager contextManager, StepInstance stepInstance)
{
HandleBlockSwitch(stepInstance.StepDefinitionType.ToScenarioBlock());
Expand Down
56 changes: 56 additions & 0 deletions Tests/TechTalk.SpecFlow.Specs/Features/ScopedHooks.feature
Original file line number Diff line number Diff line change
Expand Up @@ -133,4 +133,60 @@ Scenario: Two hooks for the same event with same name but in different classes a
When I execute the tests
Then the hook 'Hook1' is executed once
And the hook 'Hook2' is executed once


Scenario: One hook scoped on HookAttribute with two tags are executed once
Given there is a feature file in the project as
"""
Feature: Simple Feature
@mytag @mySecondTag
Scenario: Simple Scenario
When I do something
"""
And all steps are bound and pass
And the following binding class
"""
[Binding]
public class Hooks
{
[BeforeScenario("mytag", "mySecondTag")]
public void BeforeScenarioHook()
{
System.IO.File.AppendAllText(System.IO.Path.Combine(NUnit.Framework.TestContext.CurrentContext.TestDirectory, "hooks.log"), "-> hook: Hook1");
}
}
"""
When I execute the tests
Then the hook 'Hook1' is executed once


Scenario: One hook with two tags and [Scope] scoping are executed once
Given there is a feature file in the project as
"""
Feature: Simple Feature
@mytag @mySecondTag
Scenario: Simple Scenario
When I do something
"""
And all steps are bound and pass
And the following binding class
"""
[Binding]
public class Hooks
{
[BeforeScenario()]
[Scope(Tag="mytag")]
[Scope(Tag="mySecondTag")]
public void BeforeScenarioHook()
{
System.IO.File.AppendAllText(System.IO.Path.Combine(NUnit.Framework.TestContext.CurrentContext.TestDirectory, "hooks.log"), "-> hook: Hook1");
}
}
"""
When I execute the tests
Then the hook 'Hook1' is executed once

0 comments on commit 32b6938

Please sign in to comment.