0

My project has multiple feature files, where different features still share the same Background set up. Currently these Backup steps are replicated across the feature files; if I could place these common steps in a single feature this would allow the steps to be specified once and have them specified at the start of the 'sub' feature files and basically stop the tedious replication of the background steps across the features.

From my searches, I found a reference to 'steps' definitions - I'm probablty interpreting this incorrectly, but doesn't this:

steps %{
    When I go to the search form
    And I fill in "Query" with "#{query}"
    And I press "Search"
  }
end

just replicate the step definitions, which means that my features will look almost identical to the way they do just now (except with the addition of 'Steps %{ ...}end')?

Or is what I'm looking for just not possible?

The Ghost
  • 681
  • 1
  • 6
  • 15
  • Or is this the death-knell to my aspiration: http://stackoverflow.com/questions/23832979/can-features-be-called-from-other-features-in-cucumber?rq=1 – The Ghost Jan 26 '17 at 11:36
  • What you have mentioned is nested steps... You would just be writing a single step instead of multiple steps in your feature file so the inheritance part is unfulfilled. Lot of folks suggest against using this approach. How about using the Before global hook with tag filters for these steps, though if these are integral to how the scenario works it would be not advisable as you would be hiding critical steps in the code. – Grasshopper Jan 26 '17 at 12:42

2 Answers2

3

The short answer, no. Feature files can't inherit from another feature file.

The longer answer is that if you have common setup that you want to happen in many different execution, consider hiding the setup in the helper class your steps delegate to. In many cases, the implementation of a step is a delegation to another object that actually perform the work. Many steps are just one line long. Some are longer, but seldom more than two or three.

A common background is to login in a system. Login is important but it can often be hidden in the steps. The stakeholders usually don't care about things like that. They tend to care about the business behaviour. Therefore, repeating thing like login is often just noise to them and can safely be hidden in an abstraction.

My approach would be to hide common stuff, probably a duplication, down in the stack. Hide it somewhere among the step implementations.

Your situation may be different.

Thomas Sundberg
  • 4,098
  • 3
  • 18
  • 25
  • Thanks for the answer. I think I need to replicate the background across the features as there are a number of setup steps involved to get me to the 'common' point from which I start to fork out into the different scenarios. Hiding these steps in a helper class may be possible, but it presents 2 difficulties: 1) the setup steps become obscure (and they are not trivial steps), and 2) passing the parameter lists and maps between these steps becomes a significant overhead for the 20-odd steps involved – The Ghost Jan 27 '17 at 09:42
1

Feature files cannot inherit. You should not be trying to do any programming with feature files ever!

The way to do this is

  1. Name what your common background does.
  2. Implement a helper method using that name
  3. Include something in your feature that refers to that name
  4. As you need additional setup find new names, create new methods and have them use existing methods by calls

The naming part is important to features. The rest is programming and has no place in features.

Lets do the login example, assuming we already have the functionality to register users and login

Scenario: Users can see their previous orders
  Given I am signed in
  When I view my orders
  Then I should see my orders

# steps
Given 'I am signed in' do
  sign_in user: @i
end

# Helper methods
module SignInStepHelper
  def sign_in(user:)
    register(user)
    ...
  end
end
World SignInStepHelper

Now you can apply this pattern to any level of complexity, because once you get to the module part of your stack you are in a programming language, and here you can program any level of complexity into a single method call.

The secret is pushing 'HOW' you do this down so its at a lower level than the step definitions. Combine this with naming and you can deal with any level of complexity.

For example lets deal with a registered customer doing a repeat order of their monthly stationery

Scenario: Repeat order of monthly stationery

Given I am registered
And I have a monthly stationery order
When I repeat my monthly order
Then I should see my order in the checkout
And I should see my previous orders

# some steps
Given 'I have a monthly stationery order' do
  create_monthly_order(
    products: stationery_order,
    user: @i
  )
end

# implementation
module OrdersStepHelper
  def create_monthly_order(products:, user:)
    ...
  end

  def stationery_products
   [
     ...
  end
end

Now clearly there is a lot more code required to make this work, but because this is pushed down below the step definitions this is just straightforward programming. So you'll need methods like stationery_order, add_stock etc. However if you are doing BDD by the time you get to implementing this behaviour you will have most of the other stuff done and available to you.

When cuking I have a hierarchy in mind which is

features
step definitions
step helpers
application

The further down this stack I can push code that does stuff the better my experience will be.

diabolist
  • 3,990
  • 1
  • 11
  • 15