1

I'm trying to understand Gherkin, enough that I can separate out the user stories and allow the business expert to write them.

If I have a Background (version 1), a common precondition, why do all my Scenarios get errors telling me "Multiple step definitions match", isn't that the point of Background, to be common for all?

If I have different Given statements (version 1), then shouldn't the When that follows allow the same action, based on different starting positions? Again, the When causes "Multiple step definitions match"

Here is my feature file. Ideally I want Version 1, this is how the business expert is writing them, separate, easy to read but the only way to get this working without "Multiple step definitions match" errors is Version 2, where each When needs to be a combination, more complex, harder to read.

Why can't I use Background with more than 1 Scenario?

These forced changes smell, so what am I doing wrong, what have I missed? I have found hundreds of simple examples, but I feel I am missing some sort of guiding principle of Gherkin. What am I missing?

Feature: Help
    When users says help
    "As a user
    I want the bot to understand me when I ask for help, 
    In order that I get some guidance, or some idea what to do next"

  # Version 1
    Background: 
      Given the user is in conversation with the bot
      *// above line causes error*

    Scenario: No topic
        Given there is no topic
         When the user says help
         *// above line causes error*
         Then the bot responds with a sorry, regretful message
          And then asks if the user would like to see a list of available features

    Scenario: A valid topic
        Given there is a valid topic
         When the user says help
         *// above line causes error*
         Then the bot responds with a confirmation message
          And then asks if the user would like to see a list of topic features

  # Version 2
    # Scenario: All
    #     Given the user is in conversation with the bot
    #      When the user says help and there is no topic
    #      Then the bot responds with a sorry, regretful message
    #       And then asks if the user would like to see a list of available features
    #      When the user says help and there is a valid topic
    #      Then the bot responds with a confirmation message
    #       And then asks if the user would like to see a list of topic features


Failures:

1) Scenario: No topic # features/help.feature:10
   ✖ Given the user is in conversation with the bot
       Multiple step definitions match:
         the user is in conversation with the bot - tests/feature_definitions/help_definition.js:4 
         the user is in conversation with the bot - tests/feature_definitions/help_definition.js:21
   - Given there is no topic # tests/feature_definitions/help_definition.js:7
   ✖ When the user says help
       Multiple step definitions match:
         the user says help - tests/feature_definitions/help_definition.js:10
         the user says help - tests/feature_definitions/help_definition.js:27
   - Then the bot responds with a sorry, regretful message # tests/feature_definitions/help_definition.js:13
   - And then asks if the user would like to see a list of available features # tests/feature_definitions/help_definition.js:16

2) Scenario: A valid topic # features/help.feature:16
   ✖ Given the user is in conversation with the bot
       Multiple step definitions match:
         the user is in conversation with the bot - tests/feature_definitions/help_definition.js:4 
         the user is in conversation with the bot - tests/feature_definitions/help_definition.js:21
   - Given there is a valid topic # tests/feature_definitions/help_definition.js:24
   ✖ When the user says help
       Multiple step definitions match:
         the user says help - tests/feature_definitions/help_definition.js:10
         the user says help - tests/feature_definitions/help_definition.js:27
   - Then the bot responds with a confirmation message # tests/feature_definitions/help_definition.js:30
   - And then asks if the user would like to see a list of topic features # tests/feature_definitions/help_definition.js:33
Greg Burghardt
  • 17,900
  • 9
  • 49
  • 92
macasas
  • 497
  • 6
  • 20
  • There are multiple step definitions whose regular expression matches one or more steps in each of your scenarios. Which language are you using to implement steps? Seems like you have two methods to implement `When the user says help`. – Greg Burghardt Oct 16 '19 at 18:10
  • I'm using cucumber-js. It seems very restrictive to have to uniquely globally describe everything. Do you spend all your time explaining to the business user that his user stories need to be written in a different way, because I cannot change the cucumber definition without changing the gherkin feature description that matches it, and I'm not writing the gherkin feature. – macasas Oct 16 '19 at 18:39
  • If you need two different definitions for the same step then it sounds like you need two different test projects. Are you writing cucumber tests for a web application and a web API separately? – Greg Burghardt Oct 16 '19 at 22:18
  • Please include the step definitions you are using for those steps. – Greg Burghardt Oct 17 '19 at 11:48

2 Answers2

0

Your steps have multiple definitions. Cucumber only allows one step definition per step. From what you are describing you seem to be providing one step definition for each scenario, so the two scenarios each have their own definition of When the user says help. This is the wrong way to define step definitions. Each step should only have one definition, hence the error you are getting.

The definition for When the user says help should apply to all scenarios this step is being used. It's definition should be generic.

If that same step does need to be different based on the scenario, you have a couple of options:

  1. Create a separate test project so you can have 2 globally unique definitions, since you would have 2 separate global contexts for step definitions.

  2. Parameterize the step

Parameterizing the step is probably the easiest thing, and I'll use When the user says help as an example:

Scenario: No topic
    Given there is no topic
     When the user says "help"
     Then the bot responds with a sorry, regretful message
      And then asks if the user would like to see a list of available features

The line above puts the word help inside double quotes. Generating the step definition would allow you to pass the text between the quotes as an argument to your step definition method:

When(/the user says "([^"]+)"/, function(textToSay) {
    // "speak" to the chat bot using whatever API you have defined
    chatBot.receiveMessage(textToSay);
});

Now this single step can accept multiple pieces of text:

When the user says "help"
...

When the user says "list topics"
...

When the user says "I WANT TO SPEAK TO A REAL PERSON!!!!"
Then the bot responds with "I'm sorry, Dave. I'm afraid I can't do that."

(Ok, I made that last step up, but it would be a funny response if the bot didn't understand what the user was saying)

Greg Burghardt
  • 17,900
  • 9
  • 49
  • 92
0

Thanks all for your answers. I've also been over to the cucumber slack support channel and somewhere in amongst all that thinking, the penny finally dropped.

Every example I've read shows the features file mapped 1-to-1 with a steps definition file.

In my mind, the features created the templates in the terminal window, which I then put into a step.js file, which were the files than ran in the tests, they are .js after all! The terminal templates are duplicated, and I was copying them feature-scenario into steps.js 1-to-1

It did not occur to me that the feature files remained part of the process, and were actually the step driver when the tests are running.

I now have my steps organised in a completely different folder-file structure, no longer 1-to-1 with the feature files, something no example I've seen suggests, what the user says, what the bot responds, topics etc..., and it all now makes a lot more sense and of course, it has removed all the duplicate steps.

Thanks again to everyone who pushed the thinking in the right direction :-)

macasas
  • 497
  • 6
  • 20