Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SpecFlow Ambiguity in bindings

I'm working with Spec-flow for quite some days. I am facing "Multiple matching found.Navigating to first match", while Debugging this can be solved, but when I'm running the entire solution Its failing because of Ambiguity in bindings. I'm running around 4 C sharp class files in a Single project

Feature: ConversionUnencrypted Pdf-Pdf

@mytag
Scenario Outline: ConversionUnencrypted Pdf-Pdf

    Given I get Inputs Folder and list of Files <inputFolder> then <getInputTokens>(Multiple bindings for this line)
    Given I get <outputDirectory>
    Given I set saving  Mode <ConversionMode>
    Given I convert pdf using Conversion
    Given I convert to Image <convertToFile>
    Then I compare Images <getActualImagePath> and <getExpectedImagePath> and <pageCount>

and the step definitions:

**Binding for Multiple steps is the below binding:**

First binding:

[Given(@"I get Inputs Folder and list of Files (.*) then (.*)")]
public void GivenIGetInputsFolderAndListOfFilesThen(string getInputFolder, string getInputTokens)        
{
       --logic--
}

Second binding:

[Given(@"I get (.*)")]
public void GivenIGet(string getOutputDirectory)
{
      --logic--
}

Second binding modified to:

Given I set OutputDirectory of Pdf <outputDirectory>

[Given]
public void Given_I_set_OutputDirectory_of_Pdf_P0(string p0)
{
  --logic--
}

This one is also not helping me either. Have tried Regex too still could not resolve the Issue. There is a Ambiguity in the above mentioned 2 Bindings. Its not just in one feature its observed other Features file too. How can this be solved so that each line matches exactly to one Binding ?

like image 769
Jp Reddy Avatar asked Jun 15 '15 13:06

Jp Reddy


People also ask

How can ambiguous step binding implementations be resolved?

Answer: Specflow provides a mechanism to avoid ambiguous Step binding implementation using a concept called Scoped Bindings. This is useful in scenarios where you have similar steps in Scenarios in same or different feature files and if you want to treat both the Steps differently.

What is binding attribute in SpecFlow?

The automation that connects the specification to the application interface has to be developed first. The automation that connects the Gherkin specifications to source code is called a binding. The binding classes and methods can be defined in the SpecFlow project or in external binding assemblies.

How do you lower scope binding in SpecFlow?

You can restrict the execution of scoped bindings by: tag. feature (using the feature title) scenario (using the scenario title)

Which attribute in SpecFlow binds the class to step file?

You have to add the [Binding] attribute to the class where your step definitions are: [Binding] public class StepDefinitions { ... } > Note: Bindings (step definitions, hooks) are global for the entire SpecFlow project.


3 Answers

As @perfectionist has pointed out your problem is with your regexes. One is consuming all of the chars for both. Try this instead:

Feature: ConversionUnencrypted Pdf-Pdf

@mytag
Scenario Outline: ConversionUnencrypted Pdf-Pdf

    Given I get Inputs Folder and list of Files '<inputFolder>' then '<getInputTokens>'
    Given I get '<outputDirectory>'
    ...

and the step definitions:

[Given(@"I get Inputs Folder and list of Files '([^']*)' then '([^']*)'")]
public void GivenIGetInputsFolderAndListOfFilesThen(string getInputFolder, string getInputTokens)        
{
}

[Given(@"I get '([^']*)'")]
public void GivenIGet(string getOutputDirectory)
{
      --logic--
}

This regex will match only when the input doesn't contain a ' character so will prevent the second method being too greedy when consuming the input and matching the longer method.

As a general rule I prefer to wrap string characters in single quotes like above in the scenario, as it makes issues like this slightly easier to mitigate

Obviously the above will only work if your inputs '<inputFolder>','<getInputTokens>' and <outputFolder> do not contain any ' characters. If they do then you may need a more complicated regex

like image 171
Sam Holder Avatar answered Oct 25 '22 23:10

Sam Holder


You need to use Scoped Bindings so that scenarios and steps with the same descriptions can be partitioned. See the walk-through here:

http://www.specflow.org/documentation/Scoped-bindings/

or here:

https://github.com/techtalk/SpecFlow/wiki/Scoped-bindings

like image 25
James Lucas Avatar answered Oct 25 '22 23:10

James Lucas


I think I can guess the piece of missing information.

The problem is in the binding for these two lines:

Given I get Inputs Folder and list of Files <inputFolder> then <getInputTokens>
Given I get <outputDirectory>

The first binding you've given:

[Given(@"I get Inputs Folder and list of Files (.*) then (.*)")]
public void GivenIGetInputsFolderAndListOfFilesThen(string getInputFolder, string getInputTokens)        
{
    // etc
}

I'm guessing the second binding.

[Given(@"I get (.*)")]
public void GivenIGet(string outputDirectory)        
{
    // etc
}

The second binding matches any text starting with "Given I get", including of course any text that starts "Given I get Inputs Folder and list of Files ..."

If you want to avoid binding conflicts you will need to be much more specific with the "given I get " binding. When doing this you should choose language that a business expert (not a code expert) would understand for your steps - "I get " probably isn't something the business expert would say. But it might be, in highly technical organisations - in which case, you'll need to make the Regex to match a filepath/uri more specific.

Specflow cannot be used effectively without understanding Regex. (.*) is the most permissive capture group possible, and even though it is given by default by the specflow plug in, it is rarely a good answer. To get a quick list of characters you can use, and to test regex ideas out, why not look at rubular.com.

like image 43
perfectionist Avatar answered Oct 26 '22 00:10

perfectionist