Skip to content

Instantly share code, notes, and snippets.

@jarl-dk
Created April 24, 2016 19:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jarl-dk/c4670e0d0b95d08619a54cbb93c1059e to your computer and use it in GitHub Desktop.
Save jarl-dk/c4670e0d0b95d08619a54cbb93c1059e to your computer and use it in GitHub Desktop.

Cucumber directory structure

We (the cucumber team) are missing to set a convention for a directory structure on JVM projects that are using cucumber.

Background

I have for many years used cucumber for a ruby-on-rails (and also some ruby-non-rails) projects.

I have get used to the directory structure:

my-project
└── features
    ├── *.feature
    ├── step_definitions
    │   └── *_steps.rb
    └── support
        └── env.rb

I am now working on a Groovy and Grails project. So we are using the cucumber-jvm version to which there is a package for each jvm language. So we are using info.cukes:cucumber-groovy:1.2.4 package.

I am in a clean up phase and is therefore looking for a convention for using cucumber on a groovy and grails project. For those of you who don't know it the convention in grails projects is to use gradle as the build tool.

The grails framework is a convention-over-configuration framework, just like RubyOnRails. However there seems to be no one convention using cucumber in a Grails project (or any other cucumber-JVM based project).

Existing conventions

Convention on JVM projects

Gradle (and therefore also Grails) projects (and maven and in generally JVM projects) have a convention on directory base structure like this

my-project
└── src
    ├── main
    │   ├── groovy
    │   │   └── <package structure>
    │   ├── java
    │   │   └── <package structure>
    │   └── resources (directory)
    └── test
        ├── groovy
        │   └── <package structure>
        ├── java
        │   └── <package structure>
        └── resources (directory)

The groovy and java directories may not exists if there are no files in that language.

Grails have extended this convention with integration-test (to seperate integration tests from unit test), like this:

my-project
└── src
    ├── integration-test
    │   ├── groovy
    │   │   └── <package structure>
    │   ├── java
    │   │   └── <package structure>
    │   └── resources (directory)
    ├── main
    │   ├── groovy
    │   │   └── <package structure>
    │   ├── java
    │   │   └── <package structure>
    │   └── resources (directory)
    └── test
        ├── groovy
        │   └── <package structure>
        ├── java
        │   └── <package structure>
        └── resources (directory)

Existing Conventions using cucumber on JVM projects

So far I have found up to 3 conventions to use cucumber-jvm:

  1. The cucumber for java book.
  2. Official skeleton and examples.
  3. The defaults from the gradle plugin: https://github.com/samueltbrown/gradle-cucumber-plugin

This is not taking in consideration the default value for directory arguments (such as --glue) or default final argument (the directory with feature files) of the cucumber CLI tool.

Directory structure used in The cucumber for java book

The book basically does not make a stance on this subject at all, which I by itself find sad because that was one of the few things that I had hoped to find in this book. However the examples (from Chapter 2, First taste and Chapter 14, Controlling cucumber)

my-project
├── features
│   └── *.feature
└── step_definitions (this directory structure is also the package structure)
    ├── hooks
    │   └── *Hooks.java
    ├── widgets
    │   └── *Steps.java
    └── other_sub_package
        └── *Steps.java

So the glue code on relies in the JVM package step_definitions. Notice that these examples differ from the standard packaging convention in the JVM world. The convention on packaging standard is to use organisational domain prefix like dk.softace.my-project.* (or at least my-project). Note also that step definitions and hooks lives in the same package, which is not optimal since step definitions may very well be usable across projects, where as hooks is usually very specific to the project in hand and not reusable.

Cucumber examples

Both the (official) Java skeleton and groovy example follows the JVM project directory standard as sketched out above. The project is in the package skeleton, and calc respectively, not quite following convention like info.cukes.skeleton or similar.

In the Java skeleton, the files (and classes) containing the step definitions are named Stepdefs, not *Steps as would be more natural.

In the Groovy example the glue file/class (CalculatorSteps) contains all three types of glue; step definitions (Given, etc) , hooks (Before and After), and environment setup (World)

Convention in gradle-cucumber-plugin

Disclaimer: This section may not be perfectly clear nor correct. The project is pre-1.0 release and is under development, the documentation differ a bit from the implementation and it is not clear which one is ahead of the other.

The gradle plugin is true to the convention in the gradle world and it therefore proposes a directory as an extension to the standard JVM project structure by introducing cucumber along side main and test (and integrations-test in case of Grails project). This makes sense (to me) because glue code is not test code by itself, it is ... glue code. The tests are feature files.

So the directory structure looks like this:

my-project
└── src
    ├── cucumber
    │   ├── groovy
    │   │   └── <package structure>
    │   ├── java
    │   │   └── <package structure>
    │   └── resources (directory)
    │       └── *.feature
    ├── main
    │   ├── groovy
    │   │   └── <package structure>
    │   ├── java
    │   │   └── <package structure>
    │   └── resources (directory)
    └── test
        ├── groovy
        │   └── <package structure>
        ├── java
        │   └── <package structure>
        └── resources (directory)

The documentation says that if you do not configure this, the default behaviour is to look under src/test/resources for features and src/test/java for glue code. I think it is because it falls back the the cucumber-jvm defaults.

The plugin also only mentions using the groovy package info.cukes:cucumber-groovy, but I think it will also make sense (work) using another cucumber-JVM package. However it is a Gradle plugin.

Proposal for official convention

I will here come with a (incomplete) proposal for an official convention using cucumber for JVM projects. It is only a proposal and I hope pros and cons will be discussed openly.

Whatever becomes the output of this discussion I hope we (the cucumber team) will

  1. Implement this convention as default directory values in all JVM packages.
  2. Update documentation to emphasize the convention.
  3. Update all known examples to follow this convention.

I am eager to put a descent amount of effort into updating documentation and examples. I am also willing to work on updating the implementation, however I have no development history on the cucumber-jvm implementation, so others may overtake me there.

Proposed directory structure

I think the gradle plugin has made a good decision to introduce the cucumber section in a standard JVM project structure and I suggest that we elevate that to official cucumber convention. In addition to that I suggest that we make a convention for glue code packages and distinguish between

  • step definitions
    • *Steps.java and *Steps.groovy containing Given, When, etc.
  • hooks
    • *Hooks.java and *Hooks.groovy containing Before, After, etc.
  • environment setup (known as env.rb in ruby)
    • env.groovy or env.java containing miscelanous execution setup, hereamong World, etc.

So a dir layout would look like this (for groovy):

my-project
└── src
    ├── cucumber
    │   ├── groovy
    │   │   └── step_definitions
    │   │   │   └── *Steps.groovy
    │   │   ├── hooks.groovy
    │   │   └── support
    │   │       └── env.groovy
    │   └── resources (directory)
    │       └── *.feature
    ├── main
    │   ├── groovy
    │   │   └── <package structure>
    │   ├── java
    │   │   └── <package structure>
    │   └── resources (directory)
    └── test
        ├── groovy
        │   └── <package structure>
        ├── java
        │   └── <package structure>
        └── resources (directory)

Here is a quite drastic alternative. Cucumber tests are written in Gherkin, they are tests (source code written in Gherkin), not resources. Having that in mind the should be put a directory called gherkin, like this:

my-project
└── src
    ├── cucumber
    │   ├── groovy
    │   │   └── step_definitions
    │   │   │   └── *Steps.groovy
    │   │   ├── hooks.groovy
    │   │   └── support
    │   │       └── env.groovy
    │   ├── gherkin
    │   │   └── *.feature
    │   └── resources
    │       └── <static fixture files>
    ├── main
    │   ├── groovy
    │   │   └── <package structure>
    │   ├── java
    │   │   └── <package structure>
    │   └── resources (directory)
    └── test
        ├── groovy
        │   └── <package structure>
        ├── java
        │   └── <package structure>
        └── resources (directory)
@Chuckv
Copy link

Chuckv commented Apr 27, 2016

I would define a feature file as a SPEC. (it's an executable specification) as that is the primary purpose, driving the shared understanding of how the product works. Yes it is parsed and used to drive tests that validate the product is behaving as expected, but the 'test code' per say is all in the step files and any helper methods etc that the steps call.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment