cuke4duke javazone 2009
DESCRIPTION
Aslak Hellesøy presents Cuke4Duke (Cucumber on the JVM) at JavaZone 2009.TRANSCRIPT
Aslak Hellesøy - Chief Scientist
twitter.com/[email protected]
A Cuke for Dukehttp://github.com/aslakhellesoy/cuke4duke
http://www.flickr.com/photos/twose/887903401/
http://www.flickr.com/photos/twose/887903401/
55000 downloads
http://www.flickr.com/photos/twose/887903401/
1350 followers55000 downloads
http://www.flickr.com/photos/twose/887903401/
125 contributors1350 followers55000 downloads
http://www.flickr.com/photos/twose/887903401/
125 contributors1350 followers55000 downloads
56 wiki pages
http://www.flickr.com/photos/twose/887903401/
125 contributors1350 followers55000 downloads
40 tools56 wiki pages
http://www.flickr.com/photos/twose/887903401/
125 contributors1350 followers55000 downloads
40 tools8 screencasts
56 wiki pages
http://www.flickr.com/photos/twose/887903401/
125 contributors1350 followers55000 downloads
40 tools8 screencasts
56 wiki pages
1 bookhttp://www.flickr.com/photos/twose/887903401/
Outside-In
features
srcsubmit_guess.feature
test/java/codebreakerGameSteps.java
Feature: code-breaker submits guess In order to make time pass when I'm alone As a player I want to play the against a machine
Scenario: all correct Given the secret code is "r g y c" When I guess "r g y c" Then the mark should be "bbbb"
submit_guess.feature
GivenWhen
Then
GivenWhen
Then
GameSteps.java
package codebreaker;import cuke4duke.*;
public class GameSteps {}
features
srcsubmit_guess.feature
test/java/codebreakerGameSteps.java
$ gem install cucumber$ cucumber features
<repositories> <repository> <id>cukes</id> <url>http://cukes.info/maven</url> </repository> </repositories>
<pluginRepositories> <pluginRepository> <id>cukes</id> <url>http://cukes.info/maven</url> </pluginRepository> </pluginRepositories>
<dependencies> <dependency> <groupId>cuke4duke</groupId> <artifactId>cuke4duke</artifactId> <version>0.1.4</version> </dependency> <dependency> <groupId>org.picocontainer</groupId> <artifactId>picocontainer</artifactId> <version>2.8.3</version> </dependency> </dependencies>
<plugin> <groupId>cuke4duke</groupId> <artifactId>cuke4duke-maven-plugin</artifactId> <configuration> <jvmArgs> <jvmArg> -Dcuke4duke.objectFactory= cuke4duke.internal.java.PicoFactory </jvmArg> </jvmArgs> <cucumberArgs> <cucumberArg>${basedir}/src/test/java</cucumberArg> </cucumberArgs> <gems> <gem>cucumber:0.3.100</gem> </gems> </configuration> </plugin>
features
srcsubmit_guess.feature
test/java/codebreakerGameSteps.java
$ mvn integration-test \ -Dcucumber.installGems=true
pom.xml
Feature: code-breaker submits guess In order to make time pass when I'm alone As a player I want to play the against a machine
Scenario: all correct # features/c..s.feature:6 Given the secret code is "r g y c" # features/c..s.feature:7 When I guess "r g y c" # features/c..s.feature:8 Then the mark should be "bbbb" # features/c..s.feature:9
1 scenario (1 undefined)3 steps (3 undefined)0m0.076s
Undefined Steps
You can implement step definitions for undefined steps with these snippets:
@Given("^the secret code is \"([^\"]*)\"$")@Pendingpublic void theSecretCodeIsRGYC_(String arg1) {}
@When("^I guess \"([^\"]*)\"$")@Pendingpublic void iGuessRGYC_(String arg1) {}
@Then("^the mark should be \"([^\"]*)\"$")@Pendingpublic void theMarkShouldBeBbbb_(String arg1) {}
Snippets
GameSteps.javapackage codebreaker;import cuke4duke.*;
public class CodeBreakerSteps { @Given("^the secret code is \"([^\"]*)\"$") @Pending public void theSecretCodeIs(String code) { }
@When("^I guess \"([^\"]*)\"$") @Pending public void iGuess(String guess) { }
@Then("^the mark should be \"([^\"]*)\"$") @Pending public void theMarkShouldBe(String mark) { }}
Feature: code-breaker submits guess In order to make time pass when I'm alone As a player I want to play the against a machine
Scenario: all correct # features/c..s.feature:6 Given the secret code is "r g y c" # public void theS..(..) TODO (Cucumber::Pending) f../c..s.feature:7:in `Given the secret code is "r g y c"' When I guess "r g y c" # public void iGue..(..) Then the mark should be "bbbb" # public void theM..(..)
1 scenario (1 pending)3 steps (2 skipped, 1 pending)0m0.079s
$ mvn integration-test
Given the secret code is "r g y c" # public void codebreaker.GameSteps .theSecretCodeIs(java.lang.String)
Location
public class GameSteps { private Game game;
@Given("^the secret code is \"([^\"]*)\"$") public void theSecretCodeIs(String code) { game = new Game(code); }}
Implement Intention
Compilation failure
src/test/java/codebreaker/CodeBreakerSteps.java:[6,12] cannot find symbolsymbol : class Gamelocation: class codebreaker.CodeBreakerSteps
features
srcsubmit_guess.feature
main/java/codebreakerGame.java
test/java/codebreakerGameSteps.java
Game.java
package codebreaker; public class Game { public Game(String code) { }}
Feature: code-breaker submits guess In order to make time pass when I'm alone As a player I want to play the against a machine
Scenario: all correct # features/c..s.feature:6 Given the secret code is "r g y c" # public void theS..(..) When I guess "r g y c" # public void iGue..(..) TODO (Cucumber::Pending) f../c..s.feature:8:in `When I guess "r g y c"' Then the mark should be "bbbb" # public void theM..(..)
1 scenario (1 pending)3 steps (1 skipped, 1 pending, 1 passed)0m0.112s
$ mvn integration-test
Steps & Step Definitions
Given the secret code is "r g y c"
@Given("^the secret code is \"([^\"]*)\"$")public void theSecretCodeIs(String code) { game = new Game(code);}
Step == Method invocation
Steps & Step Definitions
Given the secret code is "r g y c"
@Given("^the secret code is \"([^\"]*)\"$")public void theSecretCodeIs(String code) { game = new Game(code);}
Feature: code-breaker submits guess In order to make time pass when I'm alone As a player I want to play the against a machine
Scenario: all correct # features/c..s.feature:6 Given the secret code is "r g y c" # public void theS..(..) When I guess "r g y c" # public void iGue..(..) Then the mark should be "bbbb" # public void theM..(..)
1 scenario (1 passed)3 steps (3 passed)0m0.121s
$ mvn integration-test
Scenario: all correct Given the secret code is "r g y c" When I guess "r g y c" Then the mark should be "bbbb"
Scenario: 2 wrong pos, 2 correct Given the secret code is "r g y c" When I guess "r g c y" Then the mark should be "bbww"
More Scenarios
Scenario: all correct # features/c..s.feature:6 Given the secret code is "r g y c" # public void theS..(..) When I guess "r g y c" # public void iGue..(..) Then the mark should be "bbbb" # public void theM..(..)
Scenario: all correct # features/c..s.feature:6 Given the secret code is "r g y c" # public void theS..(..) When I guess "r g y c" # public void iGue..(..) Then the mark should be "bbbb" # public void theM..(..) org.junit.ComparisonFailure: expected:<bb[bb]> but was:<bb[ww]> (NativeException) codebreaker/CodeBreakerSteps.java:20:in `theMarkShouldBe' features/codebreaker_submits_guess.feature:14:in `Then the mark should be "bbww"'
1 scenario (1 failed, 1 passed)3 steps (1 failed, 3 passed)0m0.121s
Time to write the
algorithm...
Scenario: all correct Given the secret code is "r g y c" When I guess "r g y c" Then the mark should be "bbbb"
Scenario: 2 wrong pos, 2 correct Given the secret code is "r g y c" When I guess "r g c y" Then the mark should be "bbww"
DRY?
Scenario Outline: submit guess Given the secret code is "<code>" When I guess "<guess>" Then the mark should be "<mark>"
Examples: | code | guess | mark | | r g y c | r g y c | bbbb | | r g y c | r g c y | bbww | | r g y c | y r g c | bwww | | r g y c | c r g y | wwww |
Scenario Outline
Gherkin
OH HAI: STUFFING MISHUN: CUCUMBR I CAN HAZ IN TEH BEGINNIN "3" CUCUMBRZ WEN I EAT "2" CUCUMBRZ DEN I HAZ "2" CUCUMBERZ IN MAH BELLY AN IN TEH END "1" CUCUMBRZ KTHXBAI!
Multiline args (String)Then [email protected] should get email """ Hi [email protected] Congratulations, Cucumberer was accepted. See you at JavaZone! """
@Then("^(.*) should get email$")public void email(String email, String body) {}
Multiline args (Tables)Given the following proposals | email | title | | [email protected] | Cucumber | | [email protected] | Webrat |
@Given("^the following proposals$")public void proposals(cuke4duke.Table proposals) {}
Hooks@Before
@After
Feature: Notification emails Background: Given the following proposals | email | title | | [email protected] | Cucumber | | [email protected] | Webrat |
Scenario: Approve all
Scenario: Reject Webrat
Background
Tagged Hooks@Before("@im_special,@me_too")
@me_tooFeature: Lorem Scenario: Ipsum Scenario: Dolor
Feature: Sit @im_special Scenario: Amet Scenario: Consec
Feature: Take over the world I want it all
@spanish @french @english Scenario: Take over Europe @spanish @english Scenario: Take over America
@english Scenario: Take over Australia
Tagged Execution
Feature: Take over the world I want it all
@spanish @french @english Scenario: Take over Europe @spanish @english Scenario: Take over America
@english Scenario: Take over Australia
cucumber -t spanish doit.feature
Tagged Execution
Feature: Take over the world I want it all
@spanish @french @english Scenario: Take over Europe @spanish @english Scenario: Take over America
@english Scenario: Take over Australia
Tagged Execution
Feature: Take over the world I want it all
@spanish @french @english Scenario: Take over Europe @spanish @english Scenario: Take over America
@english Scenario: Take over Australia
cucumber -t ~french doit.feature
Tagged Execution
FormattersPretty
ProgressProfileHTMLJUnitRerun
Your Own
Then /^I should have "(\d+)" cukes my belly$/ do |cukes|end
Ruby
GroovyThen "^I should have "(\d+)" cukes my belly$" { int cukes ->}
Scala (coming soon)Then("^I should have "(\d+)" cukes my belly$") { cukes:int =>}
Python, C#, F# (coming later - wire protocol)Flex (via FunFX) - alive and kicking!