Specflow calling steps within steps causes "No matching step definition" error - specflow

I am following the technique outlined here
using a step defined like
[Given("some base scenario has happened")]
public void SomeBaseScenarioHasHappened()
{
Given("some condition");
And("some action");
When("some result");
}
from a scenario like
Scenario: Some dependant scenario
Given some condition
And some base scenario has happened
When some other action
Then some other result
However the step
When some other condition
produces the following error
-> No matching step definition found for the step. Use the following code to create one:
[When(#"some other condition")]
public void Whensome other condition()
{
ScenarioContext.Current.Pending();
}
I can work around the problem by having the base scenario only use Given
[Given("some base scenario has happened")]
public void SomeBaseScenarioHasHappened()
{
Given("some condition");
Given"some action");
Given("some result");
}
however this is not what I should have to do.
Am I missing something?
Why cant the base scenario be called using an AND ?

In Specflow there are only 3 types of steps. Given, When and Then. When you use a step with And in your scenario description SpecFlow looks at the previous type of step and assumes that your And step is of the same type.
So when you write this
Scenario: Some dependant scenario
Given some base scenario has happened
And some other condition
When some other action
Then some other result
Specflow looks for step which have bindings:
Given("some base scenario has happened")
Given("some other condition")
When("some other action")
Then("some other result")
Notice there is no And binding?
So your solution is to to ensure that in your composite step you must avoid using And and just use the same binding (or one of them if they have multiple) that the original step had. Your final solution should look something like this:
[Given("some condition")]
public void SomeCondition()
{
...
}
[When("some action")]
public void SomeAction()
{
...
}
[Then("some result")]
public void SomeResult()
{
...
}
[Given("some base scenario has happened")]
public void SomeBaseScenarioHasHappened()
{
Given("some condition");
When("some action");
Then("some result");
}
[Given("some other condition")]
public void SomeOtherCondition()
{
...
}
[When("some other action")]
public void SomeOtherAction()
{
...
}
[Then("some other result")]
public void SomeOtherResult()
{
...
}
You can't use And in the composite steps because no steps are actually bound with an And, there is no such binding - The only bindings are Given, When or Then. The And and But keywords are only used when generating the unit tests that are run, the steps using those keywords are still bound to a Given, When or Then step ultimately.
In a scenario definition the things are processed in order and you can easily tell what an And step actually is based on the step it appears after, so when specflow generates the step bindings it knows what step type to use (either a Given, When or Then). When you are calling a a step from within another step you are explicitly calling one of those step bindings and you have to call it with the binding that it is bound with. So if it was bound with a Given binding like this:
[Given("some other condition")]
public void SomeOtherCondition()
{
...
}
then you have to call it like this from the code:
Given("Some other condition");
but you could refer to it like this in a scenario:
Given some condition
And some other condition
because specflow knows when it generates the unit test that the And some other condition is actually calling a Given bound step

This question has been previously answered correctly above.
I just came across the same error "No matching step definition found for one or more steps".
The reason that I had this issue, was that I had forgotten to put the attribute [Binding, Scope(Feature = "My Feature")] just above my steps c# code class which links methods to feature file, which is needed to match "Feature: My Feature" at the top of my feature file.
I just taught that I would document it here to help someone else that was seeing the same error but for the different reason that I outlined.

Possible solutions
Use Given instead of And
Scenario: Some dependant scenario
Given some base scenario has happened
Given some other condition
When some other action
Then some other result
or
Tag the step with more than one binding, e.g.
[Given(#"some other condition")]
[When(#"some other condition")]
public void Whensome other condition()
{
but this won't always make semantic sense, so use this only when it really does make sense.

try verifying if your sentence has empty spaces. i.e: Given some description(empty space)
so, in the method will appear like: [Given("some description ")]

Related

How to Ignore specflow test using programing

I want to execute specflow scenario based on some condition and skip test if condition is not met programmatically.
I have created one test which gets executed for different countries, but I want to execute test only for one country not all.
I tried scenariocontext.current.pending(); In this case steps are getting skipped but in Jenkins, test result is shown as failed.
Since SpecFlow 3.1 you can do it with the UnitTestRuntimeProvider.
[Binding]
public sealed class StepDefinitions
{
private readonly IUnitTestRuntimeProvider _unitTestRuntimeProvider;
public CalculatorStepDefinitions(IUnitTestRuntimeProvider unitTestRuntimeProvider)
{
_unitTestRuntimeProvider = unitTestRuntimeProvider;
}
[When("your binding")]
public void YourBindingMethod()
{
_unitTestRuntimeProvider.TestIgnore("This scenario is always skipped");
}
}
Ignoring is like skipping the scenario. Be careful, as it behaves a little bit different for the different unit test runners (xUnit, NUnit, MSTest, SpecFlow+ Runner).
Also, this works only in step definitions. It is not possible to use it in hooks.

Check scenario completion status in specflow in after scenario run in parallel

I have seen facets of this question asked elsewhere but there was no solid answer, so I ideally want to have a couple of [AfterScenario] bindings run and do some logic based upon the completion state, i.e did it pass/fail, and how did it fail etc.
I know there is a ScenarioContext.Current.TestError and some other related classes, but I cannot find docs that indicate if this can be used when tests are run in parallel, so is the above ScenarioContext ok to be used in this context or is there some other way to do it?
You can't use ScenarioContext.Current in parallel execution, but you can get the current ScenarioContext via Context Injection (see https://specflow.org/documentation/Context-Injection/)
So this works in parallel execution:
[Binding]
public class ScenarioStatusBinding
{
private readonly ScenarioContext _scenarioContext;
public ScenarioStatusBinding(ScenarioContext scenarioContext)
{
_scenarioContext = scenarioContext;
}
[AfterScenario]
public void CheckStatusOfScenario()
{
Console.WriteLine(_scenarioContext.TestError);
Console.WriteLine(_scenarioContext.ScenarioExecutionStatus);
}
}

No matching step binding found for this step exception

I've created a very simple feature file. When go to the definition by pressing F12. I get an error
No matching step binding found for this step.
Its being thrown for my When step.
Feature: ItemBag
Scenario Outline: Add item to bag until 200 is reached
Given I navigate to the homepage
And I search for trainers
When I add to the bag
Then trainers are added till 200 is reached
You need to create a Step file. It should be like this:
public class Steps
{
[Binding]
public void InavigateToTheHomepage()
{
this step implementation;
}
public void nextStep()
{
this step implementation;
}
}
This class should contain implementation for all of your steps. After that you shouldn't receive this kind of error.

May a scenario not have a When in BDD?

I'm currently learning/testing BDD using SpecFlow, and it works great!
Before I choose to ask my question, I have read this one, and I felt like I had to ask my question despite the fact that the same problem is addressed, because of the Exception scenario which is not mentioned.
I'm actually testing this scenario:
Scenario: I should get an error whenever I try to remove an item from an empty stack
Given I have an empty stack
When I pop from it
Then I should get an error
public class StackBehaviour {
public void GivenIHaveAnEmptyStack() { stack = new CustomStack<string>(); }
// This will throw whenever called!
// So the Then method will never be run!
// I feel like I should just put a comment which says why it's empty,
// allowing a fellow programmer to understand the exact intention.
public void WhenIPopFromIt() { stack.Pop(); }
// It is here that it verifies whether the CustomStack meets the expected behaviour.
public void ThenIShouldGetAnError() {
Assert.Throws<IndexOutOfRangeException>(delegate {
stack.Pop();
});
}
private CustomStack<string> stack;
}
public class CustomStack<T> {
public T Pop() {
if (stack.Count == 0)
throw new IndexOutOfRangeException("Cannot pop from an empty stack!");
T item = stack[stack.Count-1];
stack.RemoveAt(stack.Count-1);
return item;
}
private ArrayList stack = new ArrayList();
}
I think that leaving a comment in the When method is correct, so that the business requirement doesn't lack any information, and on the code behind, I put it clear what my intention is exactly by commenting.
What do you think? Any other ideas why I shouldn't make it?
There is another trick that you can use where the bindings help make the feature's meaning a little clearer. In this case, let's start at the end.
Then I should get an error
Your problem is a basically here, you know want an error, but you don't know how to get it. In fact you've already missed it, the error has already occurred in the When step, and in your code example, you moved the action into the then step just so you could get the error.
But what if keep the when performing the action amd re-express our then to reflect what really happens
Then I should have had an error
Seems a trivial change but now our feature reflects that the error should have been associated with the When step and we are simply evaluating it later, and that is something we can code. We just need something to remember the error in the when and deliver it to the then.
private Exception errorFromWhen = null;
public void WhenIPopFromIt()
{
try
{
stack.Pop();
}
catch(Exception ex)
{
errorFromWhen = ex;
}
}
public void ThenIShouldGetAnError()
{
errorFromWhen.ShouldNotBeNull();
errorFromWhen.ShouldBe<IndexOutOfRangeException>();
}
SpecFlow has absolutely no problems with this, in fact due to its mini Dependency injection system, you can even pass this state between binding classes if necessary.
May a scenario not have a When in BDD?
In Specflow, neither given, when or then are mandatory.
However in your example, I don't believe this is a good use of Specflow and BDD. In this answer here Marcus states:
"BDD is about ensuring that we're building the right thing, TDD is about ensuring that we're building it right."
In your example the scope of what is being tested i.e. the CustomStack, should be tested via TDD. It is the end solution that makes use of the CustomStack should be tested via BDD (and hence SpecFlow) e.g. if this CustomStack was being exercised via a certain action on a website.
This answer is also pertinent to your question.

Structure Map Generic Type Scanner

High Level
With StructureMap, Can I define a assembly scan rule that for an interface IRequestService<T> will return the object named TRequestService
Examples:
FooRequestService is injected when IRequestService<FooRequest> is requested
BarRequestService is injected when IRequestService<BarRequest> is requested
Details
I have a generic interface defined
public interface IRequestService<T> where T : Request
{
Response TransformRequest(T request, User current);
}
and then I have multiple Request objects that implement this interface
public class FooRequestService : IRequestService<Foo>
{
public Response TransformRequest(Foo request, User current) { ... }
}
public class BarRequestService : IRequestService<Bar>
{
public Response TransformRequest(Bar request, User current) { ... }
}
Now I am at the point where I need to register these classes so that StructureMap knows how to create them because in my controller I want have the following ctor (which I want StructureMap to inject a FooRequestService into)
public MyController(IRequestService<Foo> fooRequestService) { ... }
Right now to get around my issue I have implemented an empty interface and instead of having the FooRequestService implement the generic interface I have it implement this empty interface
public interface IFooRequestService : IRequestService<Foo> { }
Then my controllers ctor looks like so, which works with StructureMaps' Default Convention Scanner
public MyController(IFooRequestService fooRequestService) { ... }
How could I create a rule with StructureMap's assembly scanner to register all objects named TRequestService with IRequestService<T> (where T = "Foo", "Bar", etc) so that I don't have to create these empty Interface definitions?
To throw something else into the mix, where I am handling StructureMap's assembly scanning does not have any reference to the assembly that defines IRequestService<T> so this has to use some sort of reflection when doing this. I scanned the answer to "StructureMap Auto registration for generic types using Scan" but it seems as though that answer requires a reference to the assembly that contains the interface definition.
I am on the path of trying to write a custom StructureMap.Graph.ITypeScanner but I am kind of stuck on what to do there (mainly because I have little experience with reflection).
You are on the right path with the scanner. Thankfully there is one built into StructureMap. Unfortunately it is not yet, as of this writing, released. Get the latest from trunk and you will see a few new things available within the scanner configuration. An example for your needs is below.
public class MyRegistry : Registry
{
public MyRegistry()
{
Scan(x =>
{
x.TheCallingAssembly();
//x.AssembliesFromApplicationBaseDirectory();
x.WithDefaultConventions();
x.ConnectImplementationsToTypesClosing(typeof (IRequestService<>));
});
}
}
First you need to tell the scanner configuration which assemblies to include in the scan. The commented AssembliesFromApplicationBaseDirectory() method also might help if you are not doing a registry per assembly.
To get your generic types into the container use ConnectImplementationsToTypesClosing.
For an example on how to setup use registries when setting up the container see:
http://structuremap.sourceforge.net/ConfiguringStructureMap.htm
If you like you can skip using registries in general and just do a scan within ObjectFactory.Initialize.
Hope this helps.

Resources