Thomas Sundberg

May 29, 2014

Cucumber-JVM Hello world!

This post has been migrated to

This is the example I showed at the I T.A.K.E. Unconference 2014 in Bucharest. I created it for your convenience so you should be able to implement it yourself after the presentation.

Before we dive into the example, let me just recap what I am aiming for. I will show you how an example (or specification if you want) can be executed. The example is written in plain text and it is used as the basis for an execution. This example can later be relied upon for regression testing as well as living documentation.

I use Maven and Java in this example. If you don’t have them installed, please install them before you continue.

File structure

There are five files involved in the example. They should live this directory structure:

|-- pom.xml
`-- src
    |-- main
    |   `-- java
    |       `-- se
    |           `-- thinkcode
    |               `-- itake
    |                   `--
    `-- test
        |-- java
        |   `-- se
        |       `-- thinkcode
        |           `-- itake
        |               |--
        |               `--
        `-- resources
            `-- se
                `-- thinkcode
                    `-- itake
                        `-- belly.feature

The feature file

Let us start by examining the feature file. This is the plain text file where the example is defined. It follows a specific syntax called Gherkin.


Feature: Belly Scenario: a few cukes Given I have 42 cukes in my belly When I wait 1 hour Then my belly should growl

A feature file must start with the keyword Feature and it should be followed by a description of the feature. This description could be long and be written on many lines. It could be a user story. The description could be followed of a user story. It is all up to you how it should look like. The only important thing here is that the description is descriptive and easy to understand.

Next important thing is the Scenario. It should describe the steps that will be executed for this example. Each step begins with any of the keywords Given/When/Then and is followed by the actual step.

This is all that is needed to write a scenario in a feature. A feature may consist of many scenarios where each scenario describe a certain usage example of the system. There is only one scenario in this small example, but you can add many more.

The Cucumber runner

Some boilerplate code is needed to execute the example. I use a JUnit to execute Cucumber. It can be implemented as


package se.thinkcode.itake; import cucumber.api.junit.Cucumber; import org.junit.runner.RunWith; @RunWith(Cucumber.class) public class RunCukesTest { }

This is a very small class that only defines that it should be executed by a JUnit runner that invokes Cucumber, The class name ends with Test. This means that the Surefire plugin in Maven will be able to pick it up and execute it. The feature file must be located in the same package as the runner. Cucumber will examine its classpath and search for all files with the suffix .feature and execute any scenarios it can find.

The steps needed to execute the example are not allowed to be implemented in this class. The steps needed must be implemented in other classes.

Glue the feature to Java code

The third file needed in this example is a class that implements the actual steps that should be executed. I implement them in a utility class called StepDefinitions. This is the glue that will connect the feature files found with the actual system. My implementation looks like this:


package se.thinkcode.itake; import; import; import; import static; import static org.junit.Assert.assertThat; public class StepDefinitions { private Belly belly; private int waitingTime; @Given("^I have (\\d+) cukes in my belly$") public void i_have_cukes_in_my_belly(int cukes) throws Throwable { belly = new Belly();; } @When("^I wait (\\d+) hour$") public void i_wait_hour(int waitingTime) throws Throwable { this.waitingTime = waitingTime; } @Then("^my belly should (.*)$") public void my_belly_should_growl(String expectedSound) throws Throwable { String actualSound = belly.getSound(waitingTime); assertThat(actualSound, is(expectedSound)); } }

There are three methods defined. One for each step in the example above. Each method is annotated with a Gherkin keyword followed by a regular expression that should match the step in the feature. A regular expression group is used to find a parameter that should be picked up from the example. The first method is getting a digit that describes how many cukes that has been eaten. The steps must be located in the same package or a subpackage relative to the JUnit class that will execute Cucumber.

Global methods

The methods needed to map steps to actual Java code may be implemented in many step definition files. It was convenient to use just one in this example, but if it had made sense I could have implemented the methods in many classes. All step methods are global and visible to Cucumber. This means that the functionality needed may be implemented in more than one class. Global functions may feel horrible but there is an cunning idea behind having them global. If you describe your system using the exact same words and mean two different areas of your system, you have a larger problem than global methods. You will need to address this so parts that does different things in your system actually is described differently.

Production code

I also need some production code that actually implements my belly. It is implemented in the class Belly.


package se.thinkcode.itake; public class Belly { private int cukes; public void eat(int cukes) { this.cukes = cukes; } public String getSound(int waitingTime) { if (cukes > 41 && waitingTime >= 1) { return "growl"; } else { return "silent"; } } }

Project definition

The final thing needed to complete the example is a Maven pom that will help us get the dependencies we want and run the test. A Maven pom that satisfies this requirement is:


<?xml version="1.0" encoding="UTF-8"?> <project> <modelVersion>4.0.0</modelVersion> <groupId>se.thinkcode</groupId> <artifactId>cucumber-itake-unconference-2014</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>info.cukes</groupId> <artifactId>cucumber-java</artifactId> <version>1.1.7</version> <scope>test</scope> </dependency> <dependency> <groupId>info.cukes</groupId> <artifactId>cucumber-junit</artifactId> <version>1.1.7</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> </dependencies> </project>

Finally run the example by executing

    mvn test

in the root directory where pom.xml is located.

All dependencies will be downloaded the first time you run Maven. This may take some time.


This is a very small example, nothing more than a Hello World. It should be small enough so you are able to implement it without getting lost among all the details. It is at the same time large enough to show how you can execute a plain text example. To prove to yourself that the example actually is used, change the number of cukes eaten to 17 and re-run. This should fail. Change back to 42, re-run and watch it pass.



  1. Are you sure your above code runs? There is no feature file defined in your runner class. When i ran, I get the below message:

    T E S T S
    Running se.thinkcode.itake.RunCukesTest
    Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.386 sec <<< FAILURE!
    initializationError(se.thinkcode.itake.RunCukesTest) Time elapsed: 0.008 sec <<< ERROR!
    cucumber.runtime.CucumberException: No features found at [classpath:se/thinkcode/itake]
    at cucumber.runtime.model.CucumberFeature.load(
    at cucumber.runtime.RuntimeOptions.cucumberFeatures(
    at cucumber.api.junit.Cucumber.(
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(
    at java.lang.reflect.Constructor.newInstance(
    at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(
    at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(
    at org.junit.internal.requests.ClassRequest.getRunner(
    at org.apache.maven.surefire.junit4.JUnit4Provider.execute(
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(
    at java.lang.reflect.Method.invoke(
    at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(
    at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(
    at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(
    at org.apache.maven.surefire.booter.ForkedBooter.main(

    Results :

    Tests in error:
    initializationError(se.thinkcode.itake.RunCukesTest): No features found at [classpath:se/thinkcode/itake]

    Tests run: 1, Failures: 0, Errors: 1, Skipped: 0

    [INFO] ————————————————————————
    [INFO] ————————————————————————
    [INFO] Total time: 7.603s
    [INFO] Finished at: Wed Jun 04 13:06:08 BST 2014
    [INFO] Final Memory: 18M/157M
    [INFO] ————————————————————————
    [ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.12.2:test (default-test) on project cucumberDemo1: There are test failures.
    [ERROR] Please refer to C:\Auto Framework_Krish\cucumberDemo1\target\surefire-reports for the individual test results.
    [ERROR] -> [Help 1]
    [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
    [ERROR] Re-run Maven using the -X switch to enable full debug logging.
    [ERROR] For more information about the errors and possible solutions, please read the following articles:
    [ERROR] [Help 1]

    Comment by krish — June 4, 2014 @ 14:10

    • Hi!

      I know that my example runs. Are your sure that the feature file is in the right package in your resources directory? Your stack trace suggests that it can’t be found.

      You don’t have to define the features that should be executed in the runner class. Cucumber will use all feature files it finds on the classpath in the same package, or any subpackages, as the runner class.

      I would double check spelling of the resources directory as my first trouble shooting point to make sure I haven’t misspelled it and therefore not included the feature file in the classpath.


      Comment by Thomas Sundberg — June 5, 2014 @ 06:58

  2. Thanks, Thomas. Your straightforward, stripped-down example clears things up immensely. -A

    Comment by afekete — June 23, 2014 @ 23:08

  3. Very useful introduction, thank you

    Comment by Danny — November 25, 2014 @ 09:46

  4. really useful thanks.. On 17 it fails🙂 for any number less than 42 it will fail😉

    Comment by Abhishek — December 18, 2014 @ 14:46

  5. My .feature file is not being found. When I run the junit test I get the following output

    No features found at [classpath:se]

    0 Scenarios
    0 Steps

    Tests run: 0, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.139 sec

    Results :

    Tests run: 0, Failures: 0, Errors: 0, Skipped: 0

    [INFO] ————————————————————————
    [INFO] ————————————————————————
    [INFO] Total time: 5.816s
    [INFO] Finished at: Thu Jan 08 10:24:36 IST 2015
    [INFO] Final Memory: 5M/15M
    [INFO] ————————————————————————

    Comment by Harish — January 8, 2015 @ 05:56

    • Hi!

      It sounds to me that something is broken with your path so the feature files are not a part of the class path.

      I would start with checking the spelling of the resources directory. If you misspelled it, its will not be included in the class path and therefore not found by the Cucumber JUnit runner. Another possible problem could be that your misspelled the suffix on the feature file. It will not be picked up unless it is correct spelled.

      So, double check the directory structure, the spelling of the directories and the spelling of the suffixes for the feature files.


      Comment by Thomas Sundberg — January 8, 2015 @ 06:58

  6. […] Thomas Sundberg has a few examples showing cucumber-jvm in action. […]

    Pingback by Making acceptance testing easy, useful and fun with BDD – enter cucumber | Adventures outside the library — February 26, 2015 @ 12:25

  7. cucumber.runtime.CucumberException: Failed to instantiate class tests.SFDC.InsideSale.InsideSaleEndToEnd
    at cucumber.runtime.StepDefinitionMatch.runStep(
    at cucumber.runtime.Runtime.runStep(
    at cucumber.runtime.model.StepContainer.runStep(
    at cucumber.runtime.model.StepContainer.runSteps(
    at cucumber.api.testng.TestNGCucumberRunner.runCucumber(
    at cucumber.api.testng.AbstractTestNGCucumberTests.feature(
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(
    at java.lang.reflect.Method.invoke(
    at org.testng.internal.MethodInvocationHelper.invokeMethod(
    at org.testng.internal.Invoker.invokeMethod(
    at org.testng.internal.Invoker.invokeTestMethod(
    at org.testng.internal.Invoker.invokeTestMethods(
    at org.testng.internal.TestMethodWorker.invokeTestMethods(
    at org.testng.TestRunner.privateRun(
    at org.testng.SuiteRunner.runTest(
    at org.testng.SuiteRunner.runSequentially(
    at org.testng.SuiteRunner.privateRun(
    at org.testng.SuiteRunnerWorker.runSuite(
    at org.testng.TestNG.runSuitesSequentially(
    at org.testng.TestNG.runSuitesLocally(
    at org.testng.remote.RemoteTestNG.initAndRun(
    at org.testng.remote.RemoteTestNG.main(
    Caused by: java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(
    at java.lang.reflect.Constructor.newInstance(
    … 35 more
    Caused by: java.lang.ExceptionInInitializerError
    at salesforce.connections.ConnectionBase$connection.(
    at utils.pageobject.PageBase.(
    at tests.SFDC.InsideSale.InsideSaleEndToEnd.(
    … 40 more
    Caused by: java.lang.NullPointerException
    at java.util.Properties$LineReader.readLine(
    at java.util.Properties.load0(
    at java.util.Properties.load(
    at utils.common.ConfigPropertyProvider.accessConfigFile(
    at utils.common.ConfigPropertyProvider.(
    at salesforce.connections.ConnectionManagement.(
    … 43 more

    Total tests run: 1, Failures: 1, Skips: 0

    I am seeing this error message.. I have provided correct path on –glue and –feature on test class. Still facing this issue. Can you please help me to solve this issue? Thanks!

    Comment by Umang Patel — February 24, 2016 @ 01:26

    • Hi!

      I would check why you get a NullPointerException in your class ConfigPropertyProvider at line 28.


      Comment by Thomas Sundberg — February 24, 2016 @ 05:44

  8. This runs smoothly…🙂 those who are not able to run successfully, I would suggest to create a new maven project and copy paste all the files mentioned in this blog instead of using this stuff in existing project.

    Comment by Anil Mishra — September 21, 2016 @ 15:59

    • Hi!

      My idea is that this tutorial is not for patching an existing Cucumber setup, it is for creating a new one. The way to do that is to start fresh and do as you suggest, use these files as they are and get thing running. Then modify and understand what part does what.

      That is, you are emphasizing my idea.


      Comment by Thomas Sundberg — September 21, 2016 @ 20:22

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at

%d bloggers like this: