Cuke4Duke JavaZone 2009

60
Aslak Hellesøy - Chief Scientist twitter.com/aslak_hellesoy [email protected] A Cuke for Duke http://github.com/aslakhellesoy/cuke4duke

description

Aslak Hellesøy presents Cuke4Duke (Cucumber on the JVM) at JavaZone 2009.

Transcript of Cuke4Duke JavaZone 2009

Page 1: Cuke4Duke JavaZone 2009

Aslak Hellesøy - Chief Scientist

twitter.com/[email protected]

A Cuke for Dukehttp://github.com/aslakhellesoy/cuke4duke

Page 2: Cuke4Duke JavaZone 2009

http://cukes.info/

Page 6: Cuke4Duke JavaZone 2009

1350 followers55000 downloads

http://www.flickr.com/photos/twose/887903401/

Page 7: Cuke4Duke JavaZone 2009

125 contributors1350 followers55000 downloads

http://www.flickr.com/photos/twose/887903401/

Page 8: Cuke4Duke JavaZone 2009

125 contributors1350 followers55000 downloads

56 wiki pages

http://www.flickr.com/photos/twose/887903401/

Page 9: Cuke4Duke JavaZone 2009

125 contributors1350 followers55000 downloads

40 tools56 wiki pages

http://www.flickr.com/photos/twose/887903401/

Page 10: Cuke4Duke JavaZone 2009

125 contributors1350 followers55000 downloads

40 tools8 screencasts

56 wiki pages

http://www.flickr.com/photos/twose/887903401/

Page 11: Cuke4Duke JavaZone 2009

125 contributors1350 followers55000 downloads

40 tools8 screencasts

56 wiki pages

1 bookhttp://www.flickr.com/photos/twose/887903401/

Page 12: Cuke4Duke JavaZone 2009
Page 13: Cuke4Duke JavaZone 2009
Page 14: Cuke4Duke JavaZone 2009
Page 15: Cuke4Duke JavaZone 2009

Outside-In

Page 16: Cuke4Duke JavaZone 2009
Page 17: Cuke4Duke JavaZone 2009

features

srcsubmit_guess.feature

test/java/codebreakerGameSteps.java

Page 18: Cuke4Duke JavaZone 2009

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

Page 19: Cuke4Duke JavaZone 2009

GivenWhen

Then

Page 20: Cuke4Duke JavaZone 2009

GivenWhen

Then

Page 21: Cuke4Duke JavaZone 2009

GameSteps.java

package codebreaker;import cuke4duke.*;

public class GameSteps {}

Page 22: Cuke4Duke JavaZone 2009

features

srcsubmit_guess.feature

test/java/codebreakerGameSteps.java

$ gem install cucumber$ cucumber features

Page 23: Cuke4Duke JavaZone 2009

<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>

Page 24: Cuke4Duke JavaZone 2009

<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>

Page 25: Cuke4Duke JavaZone 2009

<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>

Page 26: Cuke4Duke JavaZone 2009
Page 27: Cuke4Duke JavaZone 2009

features

srcsubmit_guess.feature

test/java/codebreakerGameSteps.java

$ mvn integration-test \ -Dcucumber.installGems=true

pom.xml

Page 28: Cuke4Duke JavaZone 2009

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

Page 29: Cuke4Duke JavaZone 2009

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

Page 30: Cuke4Duke JavaZone 2009

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) { }}

Page 31: Cuke4Duke JavaZone 2009

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

Page 32: Cuke4Duke JavaZone 2009

Given the secret code is "r g y c" # public void codebreaker.GameSteps .theSecretCodeIs(java.lang.String)

Location

Page 33: Cuke4Duke JavaZone 2009

public class GameSteps { private Game game;

@Given("^the secret code is \"([^\"]*)\"$") public void theSecretCodeIs(String code) { game = new Game(code); }}

Implement Intention

Page 34: Cuke4Duke JavaZone 2009

Compilation failure

src/test/java/codebreaker/CodeBreakerSteps.java:[6,12] cannot find symbolsymbol : class Gamelocation: class codebreaker.CodeBreakerSteps

Page 35: Cuke4Duke JavaZone 2009

features

srcsubmit_guess.feature

main/java/codebreakerGame.java

test/java/codebreakerGameSteps.java

Page 36: Cuke4Duke JavaZone 2009

Game.java

package codebreaker; public class Game { public Game(String code) { }}

Page 37: Cuke4Duke JavaZone 2009

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

Page 38: Cuke4Duke JavaZone 2009

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

Page 39: Cuke4Duke JavaZone 2009

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);}

Page 40: Cuke4Duke JavaZone 2009

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

Page 41: Cuke4Duke JavaZone 2009

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

Page 42: Cuke4Duke JavaZone 2009

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

Page 43: Cuke4Duke JavaZone 2009

Time to write the

algorithm...

Page 44: Cuke4Duke JavaZone 2009

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?

Page 45: Cuke4Duke JavaZone 2009

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

Page 46: Cuke4Duke JavaZone 2009

Gherkin

Page 47: Cuke4Duke JavaZone 2009
Page 48: Cuke4Duke JavaZone 2009

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!

Page 49: Cuke4Duke JavaZone 2009

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) {}

Page 50: Cuke4Duke JavaZone 2009

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) {}

Page 51: Cuke4Duke JavaZone 2009

Hooks@Before

@After

Page 52: Cuke4Duke JavaZone 2009

Feature: Notification emails Background: Given the following proposals | email | title | | [email protected] | Cucumber | | [email protected] | Webrat |

Scenario: Approve all

Scenario: Reject Webrat

Background

Page 53: Cuke4Duke JavaZone 2009

Tagged Hooks@Before("@im_special,@me_too")

@me_tooFeature: Lorem Scenario: Ipsum Scenario: Dolor

Feature: Sit @im_special Scenario: Amet Scenario: Consec

Page 54: Cuke4Duke JavaZone 2009

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

Page 55: Cuke4Duke JavaZone 2009

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

Page 56: Cuke4Duke JavaZone 2009

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

Page 57: Cuke4Duke JavaZone 2009

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

Page 58: Cuke4Duke JavaZone 2009

FormattersPretty

ProgressProfileHTMLJUnitRerun

Your Own

Page 59: Cuke4Duke JavaZone 2009

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!

Page 60: Cuke4Duke JavaZone 2009