State

It’s important to prevent state created by one scenario from leaking into others. Leaking state makes your scenarios brittle, and difficult to run in isolation.

To prevent leaking state between scenarios:

  • Avoid using global or static variables.

  • Make sure you clean your database between scenarios.

Sharing state between steps

Within your scenarios, you might want to share state between steps.

It’s possible to store object state in variables inside your step definitions.

Be careful with state

State can make your steps more tightly coupled and harder to reuse.

World object

In Ruby, Cucumber runs scenarios in a World. By default, the World is an instance of Object.

All step definitions will run in the context of the current World instance; a new instance is created for each scenario. This means that self in a step definition block will be the World instance. Any @instance_variable instantiated in a step definition will be assigned to the World, and can be accessed from other step definitions.

If you want to add any behaviour to the world, like helper methods, or logging, you can do this in support/env.rb:

module CustomWorld
  def a_helper
    ...
  end
end

World(CustomWorld)

Now you can call a_helper from your step definitions.

Note that every scenario is run in a separate instance of the world, so there is no implicit state-sharing from scenario to scenario.

You can also include modules in your World:

module MyHelper
  def some_other_helper
    ...
  end
end

module CustomWorld
  include MyHelper

  def a_helper
    ...
  end
end

World(CustomWorld)

Several other frameworks such as Rspec or Webrat have modules that provide special methods that you can include in your World this way.

If you don’t want to define your own World class (and just use the default Object instances), you can still include modules in your World instances without polluting Object with a global include:

module MyHelper
  def some_other_helper
    ...
  end
end

module MyOtherHelpers
  def helper_b
    ...
  end
end

World(MyHelper, MyOtherHelpers)

This will extend each new World object with those modules.

If you use Ruby on Rails, there is already a World set up for you, so you will get an instance of Cucumber::Rails::World, which is a subclass of ActionDispatch::IntegrationTest. This gives you access to a lot of Rails’ helper methods.

For more information, have a look at Building a better World (blog post).

Cucumber-js also uses a World as an isolated context for each scenario. You can find more information in the cucumber-js documentation on GitHub.

Dependency Injection

If your programming language is Java, you will be writing glue code (step definitions and hooks) in plain old Java classes.

Cucumber will create a new instance of each of your glue code classes before each scenario.

If all of your glue code classes have an empty constructor, you don’t need anything else. However, most projects will benefit from a dependency injection (DI) module to organize your code better and to share state between step definitions.

The available dependency injection modules are:

PicoContainer

To use PicoContainer, add the following dependency to your pom.xml:

<dependency>
    <groupId>io.cucumber</groupId>
    <artifactId>cucumber-picocontainer</artifactId>
    <version>3.0.0}</version>
    <scope>test</scope>
</dependency>

Or, if you are using Gradle, add:

compile group: 'io.cucumber', name: 'cucumber-picocontainer', version: '3.0.0}'

There is no documentation yet, but the code is on GitHub. For more information, please see sharing state using Picocontainer.

Spring

To use Spring, add the following dependency to your pom.xml:

<dependency>
    <groupId>io.cucumber</groupId>
    <artifactId>cucumber-spring</artifactId>
    <version>3.0.0</version>
    <scope>test</scope>
</dependency>

Or, if you are using Gradle, add:

compile group: 'io.cucumber', name: 'cucumber-spring', version: '3.0.0}'

There is no documentation yet, but the code is on GitHub.

Guice

To use Guice, add the following dependency to your pom.xml:

<dependency>
    <groupId>io.cucumber</groupId>
    <artifactId>cucumber-guice</artifactId>
    <version>3.0.0</version>
    <scope>test</scope>
</dependency>

Or, if you are using Gradle, add:

compile group: 'io.cucumber', name: 'cucumber-guice', version: '3.0.0}'

There is no documentation yet, but the code is on GitHub. For more information, please see sharing state using Guice.

OpenEJB

To use OpenEJB, add the following dependency to your pom.xml:

<dependency>
    <groupId>io.cucumber</groupId>
    <artifactId>cucumber-openejb</artifactId>
    <version>3.0.0</version>
    <scope>test</scope>
</dependency>

Or, if you are using Gradle, add:

compile group: 'io.cucumber', name: 'cucumber-openejb', version: '3.0.0}'

There is no documentation yet, but the code is on GitHub.

Weld

To use Weld, add the following dependency to your pom.xml:

<dependency>
    <groupId>io.cucumber</groupId>
    <artifactId>cucumber-weld</artifactId>
    <version>3.0.0</version>
    <scope>test</scope>
</dependency>

Or, if you are using Gradle, add:

compile group: 'io.cucumber', name: 'cucumber-weld', version: '3.0.0}'

There is no documentation yet, but the code is on GitHub.

Needle

To use Needle, add the following dependency to your pom.xml:

<dependency>
    <groupId>io.cucumber</groupId>
    <artifactId>cucumber-needle</artifactId>
    <version>3.0.0</version>
    <scope>test</scope>
</dependency>

Or, if you are using Gradle, add:

compile group: 'io.cucumber', name: 'cucumber-needle', version: '3.0.0}'

There is no documentation yet, but the code is on GitHub.

Databases

There are several options to remove state from your database, to prevent leaking state between scenarios.

The Before Hook Approach

The recommended approach to clean a database between scenarios is to use a Before hook to remove all data before a scenario starts.

This is usually better than using an After hook, as it allows you to perform a post-mortem inspection of the database if a scenario fails.

An alternative approach is to use database transactions.

The Database Transaction Approach

If your database supports it, you can wrap a transaction around each scenario.

This might lead to faster scenarios, but it comes at a cost. You won’t be able to perform a post-mortem, and you won’t be able to use browser automation.

To use this approach, you need to tell Cucumber to start a transaction in a Beforehook, and later roll it back in an Afterhook.

This is such a common thing to do that several Cucumber extensions provide ready-to-use tagged hooks using a tag named @txn.

To enable it, you must tag every feature or scenario that requires transactions with @txn:

@txn
Feature: Let's write a lot of stuff to the DB

  Scenario: I clean up after myself
    Given I write to the DB

  Scenario: And so do I!
    Given I write to the DB

With JUnit and Spring

The cucumber-spring module contains @txn hooks in the cucumber.api.spring package.

This package isn’t on your glue path by default, so you have to add it yourself in your Cucumber Options.

@RunWith(Cucumber.class)
@CucumberOptions(glue = {"your.own.glue.code", "cucumber.api.spring"})
public class RunCukesTest {
}

See the spring-txn example in Cucumber-JVM for a minimal setup.

Browser Automation and Transactions

If you’re using a browser automation tool that talks to your application over HTTP, the transactional approach will not work if your step definitions and the web application serving HTTP request each have their own database connection. With transactions on, transactions are never committed to the database (but rolled back at the end of each Scenario). Therefore, the web server’s connection will never see data from Cucumber, and therefore your browser won’t either. Likewise, Cucumber’s connection won’t see data from the web server.

In this case, you will have to turn off database transactions and make sure the data is explicitly deleted before each Scenario.

Turn of transactions

If you’re using Ruby on Rails it’s easy to turn off transactions for a feature or particular scenarios. Use the @no-txn tag, like this:

@no-txn
Feature: Lots of Scenarios with transactions off.

If this is the case you should use the brute-force approach where the data is explicitly deleted before each scenario. Or this:

Feature: ...
  @no-txn
  Scenario: One Scenario with transactions off.

With Rails, you can also turn off transaction globally in your features/support/env.rb:

Cucumber::Rails::World.use_transactional_fixtures = false

Cleaning Your Database

If you’re using Ruby on Rails, a good tool to deal with this is Ben Mabey’s Database Cleaner gem, which you can install with gem install database_cleaner.

You can use this very effectively with the @no-txn tag. For example, add something like the following somewhere in e.g. features/support/db_cleaner.rb:

require 'database_cleaner'
DatabaseCleaner.clean_with :truncation # clean once to ensure clean slate
DatabaseCleaner.strategy = :truncation

Before('@no-txn') do
  DatabaseCleaner.start
end

After('@no-txn') do
  DatabaseCleaner.clean
end

If you’re not using Rails, you can recreate the entire @no-txn behaviour using DatabaseCleaner in Ruby with the following code:

# With this you should be able to tag the stories that need to use truncation.
# Otherwise, the transaction strategy will be used all the other times.

require 'database_cleaner'
DatabaseCleaner.clean_with :truncation # clean once to ensure clean slate
DatabaseCleaner.strategy = :transaction # use transactions by default

Before('@no-txn') do
  DatabaseCleaner.strategy = :truncation
end

Before do
  DatabaseCleaner.start
end

After do
  DatabaseCleaner.clean
end

After('@no-txn') do
  DatabaseCleaner.strategy = :transaction
end

You can help us improve this documentation. Edit this page.