SpecFlow Ambiguity in bindings

3.8k views Asked by At

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 ?

3

There are 3 answers

0
Sam Holder On BEST ANSWER

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

0
James Lucas On

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

0
perfectionist On

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.