Search code examples
cucumberacceptance-testing

Reusing cucumber steps in a large codebase/team


We're using cucumberJS on a fairly large codebase with hundreds of cucumber scenarios and we've been running into issues with steps reuse.

Since all the steps in Cucumber are global, it's quite difficult to write steps like "and I select the first item in the list" or similar that would be similarly high-level. We end up having to append "on homepage" (so: "I select the first item in the list of folders on homepage") which just feels wrong and reads wrong.

Also, I find it very hard to figure out what the dependencies between steps are. For example we use a "and I see " pattern for storing a page object reference on the world cucumber instance to be used in some later steps. I find that very awkward since those dependencies are all but invisible when reading the .feature files.

What's your tips on how to use cucumber within a large team? (Including "ditch cucumber and use instead" :) )


Solution

  • Write scenarios/steps that are about what you are doing and why you are doing it rather than about how you do things. Cucumber is a tool for doing BDD. The key word here is Behaviour, and its interpretation. The fundamental idea behind Cucumber and steps is that each piece of behaviour (the what) has a unique name and place in the application, and in the application context you can talk about that behaviour using that name without ambiguity.

    So your examples should never be in steps because they are about HOW your do something. Good steps never talk about clicking or selecting. Instead they talk about the reason Why you are clicking or selecting.

    When you follow this pattern you end up with fewer steps at a higher level of abstraction that are each focused on a particular topic.

    This pattern is easy to implement, and moderately easy to maintain. The difficulty is that to write the scenarios you have to have a profound understanding of what you are doing and why its important so you can discover/uncover the language you need to express yourself distinctly, clearly and simply.

    I'll give my standard example about login. I use this because we share an understanding of What login is and Why its important. Realise before you can login that you have to be registered and that is complex.

    Scenario: Login
      Given I am registered
      When I login
      Then I should be logged in
    

    The implementation of this is interesting in that I delegate all work to helper methods

      Given I am registered
        @i = create_registered_user
      end
    
      When I login
        login_as(user: @i)
      end
    
      Then I should be logged in
        should_be_logged_in
      end
    

    Now your problem becomes one of managing helper methods. What you have is a global namespace with a large number of helper methods. This is now a code and naming problem and All you have to do is

    • keep the number of helper methods as small as possible
    • keep each helper method simple
    • ensure there is no ambiguity between method names
    • ensure there is no duplication

    This is still a hard problem, but - its not as hard as what you are dealing with - getting to this point has a large number of additional benefits - its now a code problem, lots of people have experience of managing code.

    You can do all these things with - naming discipline (all my methods above have login in their name) - clever but controlled use of arguments - frequent refactoring and code cleaning

    The code of your helper methods will have - the highest churn of all your application code - the greatest need to be simple and clear

    So currently your problem is not about Cucumber its about debt you have with your existing scenarios and their implementation. You have to pay of your debt if you want things to improve, good luck