spacer
spacer

• Text Post

Cucumber-JVM 1.0.0

Today I am very excited to announce Cucumber-JVM 1.0.0.

Cucumber-JVM is a pure Java implementation of Cucumber, with native support for the most popular JVM languages: Java, Scala, Groovy, Clojure, Rhino, Jython and JRuby. Cucumber-JVM is the successor of Cuke4Duke, which was the Ruby implementation of Cucumber, running on JRuby. Cuke4Duke was a pain to use - it was hard to install and both slow and difficult to run.

Cucumber-JVM on the other hand is easy to install, and it’s fast and easy to run (thanks to its JUnit integration).

I will be giving an introduction to Cucumber-JVM at CukeUp! on April 4, and I am also working on documentation, but for now let me give you a quick glance of what you can do with it. We are going to create the following files:

.
|-- build.xml (Optional)
|-- pom.xml (Optional)
`-- src
    |-- main
    |   `-- java
    |       `-- cucumber
    |           `-- examples
    |               `-- java
    |                   `-- helloworld
    |                       `-- Hello.java
    `-- test
        |-- java
        |   `-- cucumber
        |       `-- examples
        |           `-- java
        |               `-- helloworld
        |                   |-- HelloStepdefs.java
        |                   `-- RunCukesTest.java
        `-- resources
            `-- cucumber
                `-- examples
                    `-- java
                        `-- helloworld
                            `-- helloworld.feature

Start by creating helloworld.feature:

Feature: Hello World
  Scenario: Say hello
    Given I have a hello app with "Howdy"
    When I ask it to say hi
    Then it should answer with "Howdy World"

Now, create a pom.xml if you want to use Maven or a build.xml if you want to use Ant. This is all you need to download Cucumber-JVM and run your features.

Next, create RunCukesTest.java which is used to run features from JUnit:

package cucumber.examples.java.helloworld;

import cucumber.junit.Cucumber;
import org.junit.runner.RunWith;

@RunWith(Cucumber.class)
@Cucumber.Options(format = {"pretty", "html:target/cucumber"})
public class RunCukesTest {
}

We are passing some options to Cucumber, telling it to generate a HTML report as well.

When you run ant download runcukes or mvn test you will see all of your steps showing up as undefined. Cucumber-JVM will print some snippets to get you started. Let’s add those snippets to HelloStepdefs.java and fill in the blanks:

package cucumber.examples.java.helloworld;

import cucumber.annotation.en.Given;
import cucumber.annotation.en.Then;
import cucumber.annotation.en.When;

import static org.junit.Assert.assertEquals;

public class HelloStepdefs {
    private Hello hello;
    private String hi;

    @Given("^I have a hello app with \"([^\"]*)\"$")
    public void I_have_a_hello_app_with(String greeting) {
        hello = new Hello(greeting);
    }

    @When("^I ask it to say hi$")
    public void I_ask_it_to_say_hi() {
        hi = hello.sayHi();
    }

    @Then("^it should answer with \"([^\"]*)\"$")
    public void it_should_answer_with(String expectedHi) {
        assertEquals(expectedHi, hi);
    }
}

Finally we need an implementation of our Hello World system in Hello.java:

package cucumber.examples.java.helloworld;

public class Hello {
    private final String greeting;

    public Hello(String greeting) {
        this.greeting = greeting;
    }

    public String sayHi() {
        return greeting + " World";
    }
}

Run Ant or Maven again, and all is green. If you would rather do all of this in Scala, Groovy, Clojure, Rhino, Jython, JRuby - or even Ioke - that’s easy too. You will find more examples here.

Some other features of Cucumber-JVM:

  • Multiple output formats: HTML, JSON, JUnit and more.
  • DI support: PicoContainer, Guice, Spring, Weld and OpenEJB.
  • Automatic conversion of step definition arguments.
  • I18n support for over 40 spoken languages
  • Grails and Play support on its way.
  • IntelliJ support is on the way.

Take it for a spin and let us know what you think!

  • 3 notes, comments
  • cucumber gherkin cucumber-jvm

• Text Post

The training wheels came off

Cucumber rounded the 1,000,000 download mark a couple of days ago, and is clearly a very popular tool. It owes a lot of its popularity to Cucumber-Rails - a Ruby gem that sets up Cucumber in a Rails project. One of the reasons Cucumber-Rails has become popular is that it is relatively easy to get started with.

Most people who learned to ride a bike as a child had training wheels. When a child learns to ride on his or her own, the training wheels are removed. Until last week, Cucumber-Rails also came with pre-mounted training wheels, in the form of a generated web_steps.rb file with 30 or so reusable step definitions.

This gave a lot of people a flying start with Cucumber and Rails. Many people never removed the training wheels. Instead they soldered them to the frame by piling up with long, verbose and brittle scenarios that depend on them.

Half a year ago we added a warning to the generated web_steps.rb, because relying on them has so many negative effects.

Some people followed this advice, but there are still a lot of people who fall into the trap. In Cucumber-Rails 1.1.0 they were removed for good, and in 1.1.1 we also removed its tricycle cousin - the cucumber:feature generator. The training wheels came off.

spacer

The reactions were exactly as I had expected. -A combination of applause and gnashing of teeth. Most of the people who disagree say something along the lines of:

This is going to make it harder for people to get started with Cucumber.

I say: this is going to make it harder for people to use Cucumber badly. Now they have to:

  1. Learn the Capybara API instead of the web_steps.rb regular expressions.
  2. Think harder about what goes into a scenario.

If this hurts the adoption of Cucumber-Rails I’m perfectly fine with it. You already have plenty of rope to hang yourself with, and I’m not going to tie the noose for you.

Let me explain why web_steps.rb is a terrible, terrible idea.

Boring scenarios

Cucumber was designed around the core principles of BDD, and one of these principles is to improve stakeholder collaboration through a ubiquitous language. This essentially means that both code and executable specifications (Cucumber scenarios) should be written in the language of the domain. The “domain” is defined by the value the stakeholders and users hope to achieve with the software. This can be booking a ticket or sharing pictures with friends or an infinite number of activities. Clicking links and buttons or filling in text fields has nothing to do with the domain.

Cucumber scenarios that consist of 10 or so steps that click links, fill in fields, push buttons and look for text are going to bore your stakeholders to death.

Their eyes will glaze over, and they won’t even spot mistakes. Even programmers will have a hard time spotting conceptual errors at this abstraction level. Using Cucumber exclusively to emulate a keyboard and a mouse is possible, but it’s not what it was designed for.

If all you need is a testing tool for driving a mouse and a keyboard, don’t use Cucumber. There are other tools that are designed to do this with far less abstraction and typing overhead than Cucumber. Capybara DSL and Steak are much better if you want a programmer/tester-only tool.

Brittle scenarios

Allowing technical details to bleed into scenarios does more harm than losing stakeholder involvement through boredom. It makes everything harder to change as well. Consider this scenario for logging in:

Scenario: Successful login
  Given a user "Aslak" with password "xyz"
  And I am on the login page
  And I fill in "User name" with "Aslak"
  And I fill in "Password" with "xyz"
  When I press "Log in"
  Then I should see "Welcome, Aslak"

If users have to log in there is usually a lot of functionality that is only accessible to users who have logged in. This means logging in has to happen before most scenarios:

Background: A logged in user
  Given a user "Aslak" with password "xyz"
  And I am on the login page
  And I fill in "User name" with "Aslak"
  And I fill in "Password" with "xyz"
  When I press "Log in"
  Then I should see "Welcome, Aslak"

You’ll have to repeat this in all of your scenarios that describe functionality for logged in users. When someone decides to allow users to log in with an email address instead of a user name we have to go over all of our scenarios and change them.

It’s not a question of if the user interface has to change, but when. Usually a UI change has far wider consequences than this example.

Where is my workflow?

Cucumber was designed to help developers with TDD at a higher level. A common challenge with conventional TDD is that developers don’t know where to start. It’s hard to figure out what tests to write.

The idea with Cucumber (and BDD in general) is that stakeholders assist in writing scenarios - or executable specifications. This solves the where do we start problem with TDD. The scenarios express what a user should be able to do, and not how. When a scenario is defined, programmers implement the required functionality.

This kind of workflow is much harder to follow when scenarios are written in a low-level, imperative style. Very few stakeholders or business analysts are going to agree to defining functionality in terms of mouse clicks and key presses. They think and talk at a higher abstraction level, and scenarios should capture that.

I don’t care about this tree hugging stuff, give me my web_steps.rb

When I started the Cucumber project in 2008 I had three major goals:

  • Help stakeholders express what they want via executable specifications
  • Help programmers write better software by making TDD/BDD easy
  • Reduce misinterpretations through a ubiquitous language

Scenarios based on web_steps.rb undermine those goals, and that is why I decided to remove them. Maybe it’s a pride thing. -Like the shopkeeper who refuses to sell merchandise he believes is of bad quality, even if doing so would mean more customers.

Unfortunately, there are books, screencasts and tutorials out there that teach you Cucumber using web_steps.rb. If web_steps.rb disappeared for good this would harm the people who are selling this training material. People who have bought it won’t get what they paid for. So I present to you: cucumber-rails-training-wheels.

This is a stillborn project. I will not accept bug reports or pull requests. The only reason it exists is to make old tutorials and books work.

Fine. I still think it’s easier to write scenarios based on web_steps.rb

Which one of these lines are easier to write?

When I press "Log in"
click_button("Log in")

I don’t think it’s harder to read the Capybara API than the regular expressions in web_steps.rb. If it is, someone needs to improve the Capybara API docs.

Can you give me an example of the new way?

Let’s take the login scenario above and make it a little more readable:

Scenario: User is greeted upon login
  Given the user "Aslak" has an account
  When he logs in
  Then he should see "Welcome, Aslak"

The step definition for the first step would create a new User record and store a reference in a @user variable. This would use ActiveRecord directly. The interesting part is logging in. Cucumber prints out snippets of code for undefined steps:

When /^he logs in$/ do
  # express the regexp above with the code you wish you had
end

Assuming we know what the log in screen is supposed to look like, we can implement this step definition:

When /^he logs in$/ do
  visit('/login')
  fill_in('User name', :with => @user.name)
  fill_in('Password', :with => @user.password)
  click_button('Log in')
end

That wasn’t so hard. Now let’s improve on that Background we had earlier so we can log in before other scenarios:

Background: The user is logged in
  Given a logged in user

Scenario: Upload a picture
  # Some steps here

When we’re describing other parts of the system that require login, the login details like user name, password and how to log in are only distracting. That is why we make it a one-liner. Let’s look at how we would define that:

Given /^a logged in user$/ do
  @user = User.create!(:name => 'Aslak', :password => 'xyz')
  visit('/login')
  fill_in('User name', :with => @user.name)
  fill_in('Password', :with => @user.password)
  click_button('Log in')
end

Can you spot the duplication with the When /^he logs in$/ step definition? Let’s improve this:

module LoginSteps
  def login(name, password)
    visit('/login')
    fill_in('User name', :with => name)
    fill_in('Password', :with => password)
    click_button('Log in')
  end
end

World(LoginSteps)

Now your two step definitions can be simplified:

When /^he logs in$/ do
  login(@user.name, @user.password)
end

Given /^a logged in user$/ do
  @user = User.create!(:name => 'Aslak', :password => 'xyz')
  login(@user.name, @user.password)
end

Not only have you made your Scenario and Background easier to read, you also isolated the login details in one single place. Changing the login process to use an email instead of a name will be easy. No scenarios have to change, and you only have to change a couple of places in your step definitions.

Conclusion

Removing the web_steps.rb training wheels makes Cucumber harder to use badly. You have to learn the Capybara API instead of regular expressions, and you will take more advantage of the snippets Cucumber prints for undefined steps. This also means you have to think in terms of the domain and not the user interface when you write scenarios. This makes them a lot easier to maintain. Short, declarative scenarios serve as easily readable documentation, and non-technical stakeholders and business analysts are more likely to get intimate with them.

There are also a couple of things you no longer have to do:

  • Wade through web_steps.rb and try to make your steps fit their mold. (You’re in charge and can say what you want)
  • Update a cryptic paths.rb or selectors.rb file
  • Be afraid to change generated code you don’t really understand

Here are some great resources for more information:

  • Refuctoring your Cukes by Matt Wynne
  • Imperative vs Declarative Scenarios in User Stories by Ben Mabey
  • Whose domain is it anyway? by Dan North
  • You’re Cuking it Wrong by Jonas Nicklas
  • Why Bother With Cucumber Testing? by Jack Kinsella

Happy cuking!

  • 25 notes, comments
  • cucumber web_steps rails

• Photo Post

spacer

So you have decided to learn to use Cucumber on your next project. You head to the Cucumber Wiki, but you still feel a little lost.

We don’t want anyone to be lost, so Matt and I have written The Cucumber Book. Well, 3/4 of it at least. You can buy the beta book today!

  • comments
  • cucumber

• Text Post

Cucumber 1.0.0

spacer

I am so thrilled about this I set up a blog!

Today I released Cucumber 1.0.0 after three years in the making. Here are some interesting numbers:

  • 740,000 downloads
  • 250 contributors (according to the git logs)
  • 1,300 Google Group members and 8300 messages
  • 630 Resolved bugs/feature requests

What’s next? I am working on a Cucumber book with Matt Wynne that will be out later this year. There is a Javascript port underway that will work both on Node.js and in browsers. When I’m done with the book I will pick up the work on a pure Java implementation that will supersede Cuke4Duke.

I would like to thank everybody on the Cucumber Google group, everybody who has reported bugs, showed it off at their companies or local user groups or promoted it in general. To the contributors who made it into git - thanks so much for giving your time and code. -And the core team, Matt Wynne, Gregory Hnatiuk, Mike Sassak, Joseph Wilk and Ben Mabey. You are awesome.

  • 6 notes, comments
  • cucumber
gipoco.com is neither affiliated with the authors of this page nor responsible for its contents. This is a safe-cache copy of the original web site.