81
John Ferguson Smart Behavior-Driven Development on the JVM A State of the Union

Bdd state-of-the-union

Embed Size (px)

Citation preview

Page 1: Bdd state-of-the-union

John  Ferguson  Smart

Behavior-Driven Development on the JVMA State of the Union

Page 2: Bdd state-of-the-union

John Ferguson Smart

ConsultantTrainerMentorAuthorSpeakerCoder

Page 3: Bdd state-of-the-union

What is BDD?

Page 4: Bdd state-of-the-union

Common Language

Business Developer

Business Analyst

Tester

Page 5: Bdd state-of-the-union

Executable Specifications

Page 6: Bdd state-of-the-union

OutsideIn

Page 7: Bdd state-of-the-union

Value Driven

Page 8: Bdd state-of-the-union

\So why use BDD?

Only build features that add real value

Less wasted effort

Better communication

Higher quality, better tested product

Traceability

Page 9: Bdd state-of-the-union

BDD - Requirements Analysis and Communication

Page 10: Bdd state-of-the-union

Examples/Scenarios

Stories

Features

Capabilities

Goals

Acceptance Criteria

Page 11: Bdd state-of-the-union

11

“We are going to build an online classifieds website”

Successful projects start with a shared vision

Page 12: Bdd state-of-the-union

12

You define goals to achieve your vision

“We can increase advertising revenue by letting sellers post their classified ads online”

“Let’s get more sales for our advertisers by making the ads easier to find online.”

Page 13: Bdd state-of-the-union

A good goal should add value to the businessIncrease revenueReduce costsAvoid future costsProtect revenue

Determining the value of a goal

“Increase advertising revenue by allowing sellers to post classified ads online”

“Reduce the costs involved in publishing a classified ad by allowing sellers to post them online themselves. ”

“Prevent current customers switching to a competing product by providing support for online credit card payments”

Page 14: Bdd state-of-the-union

What does the customer really need?

I want users to be able to search for products by keyword Why?

So that potential buyers can find the articles they want

So that our sellers can sell their stuff fasterWhy?

Why?

So that they keep selling their stuff on our siteWhy?

So that we keep earning money when they post their ads with us

Page 15: Bdd state-of-the-union

What does the customer really need?

Good teams push back!Users tend to express requirements as implementationsWe need to find the business need behind the suggested implementation

I want users to be able to search by keyword

So in order to make the site more attractive for sellersBuyers need to be able to find things easily

A search feature might be one way to achieve this

But full-text searches might be more effective than keywords

Page 16: Bdd state-of-the-union

“Let’s get more sales for our advertisers by making the ads easier to find online.”

Notify potential buyers about new itemsIn order to increase sales of advertised articlesAs a sellerI want previous buyers to know about new items that they might be interested in buying

Search for online adsIn order to increase sales of advertised articlesAs a sellerI want buyers to be able to easily find ads for articles they want to buy

Features and capabilities help deliver these goals

Page 17: Bdd state-of-the-union

Feature Injection - what features do you do first?

Our goals say what business value we need to deliverWe implement the minimum features required to deliver this business value

Search for online adsIn order to increase sales of advertised articlesAs a sellerI want buyers to be able to easily find ads for articles they want to buy

The goal comes first

The stakeholder is secondary

The feature must be required to achieve the goal

Page 18: Bdd state-of-the-union

18

We use examples and stories to explore the features

“Searching by category”

Search for online ads

“Searching by keyword and category”

Page 19: Bdd state-of-the-union

19

We use examples and stories to explore the features

Search for online ads

Searching by keyword and locationGiven  Sally  wants  to  buy  a  puppy  for  her  son  

When  she  looks  for  ‘puppy’  in  the  ‘Pets  and  Animals’  category

Then  she  should  obtain  a  list  of  ads  for  puppies  for  sale.

Page 20: Bdd state-of-the-union

20

Examples and scenarios become acceptance criteria

Acceptance Criteria illustrate and validate the stories

Searching by keyword and locationGiven  Sally  wants  to  buy  a  puppy  for  her  son  

When  she  looks  for  ‘puppy’  in  the  ‘Pets  and  Animals’  category

Then  she  should  obtain  a  list  of  ads  for  puppies  for  sale.

Scenario: Searching by keyword and location

Given Sally wants to buy a present for her son When she looks for the present in a given category Then she should obtain a list of matching ads for sale.

Examples:

Present Category Expected Keywordspuppy Pets & Animals labradorkitten Pets & Animals burmesekitten Toys fluffy cat

Page 21: Bdd state-of-the-union

Organize your requirements

Page 22: Bdd state-of-the-union

Requirements can come from many sources...

Page 23: Bdd state-of-the-union

CapabilityIn order to increase the number of items I sellAs a sellerI want buyers to be able to view ads for items they might want to purchase

FeatureIn order to increase sales of advertised articlesAs a sellerI want potential buyers to be able to display only the ads for articles that they might be interested in purchasing.

StoryIn order to find the items I am interested in fasterAs a buyerI want to be able to list all the ads with a particular keyword in the description or title.

Goal: In order to increase revenue from commissions on classified ads salesAs the head of the classified ads departmentI want to increase the number of items sold via our classified ads

Keep them organized!

Page 24: Bdd state-of-the-union

Requirements can come from many sources...

Page 25: Bdd state-of-the-union

25

BDD - Test Automation and Beyond

Page 26: Bdd state-of-the-union

26

The original Java BDD framework

Page 27: Bdd state-of-the-union

27

Narrative:In order to increase sales of advertised articlesAs a sellerI want buyers to be able to easily find ads for articles they want to buy

Scenario: Searching by keyword and location

Given Sally wants to buy a puppy for her son When she looks for 'puppy' in the 'Pets and Animals' category Then she should obtain a list of ads for puppies for sale.

search_by_keyword_and_location.story

Page 28: Bdd state-of-the-union

28

Scenario: Searching by keyword and location

Given Sally wants to buy a puppy for her son When she looks for 'puppy' in the 'Pets and Animals' category Then she should obtain a list of ads for puppies for sale.

search_by_keyword_and_location.story

Scenario: Searching by keyword and location

Given Sally wants to buy a <present> for her son When she looks for '<present>' in the '<category>' category Then she should obtain a list of ads for <expected> for sale.

Examples:|present |category |expected||puppy |Pets & Animals | puppies||kitten |Pets & Animals | kittens||seiko |Jewellery & Watches| watch |

Page 29: Bdd state-of-the-union

29

Scenario: Searching by keyword and location

Given Sally wants to buy a puppy for her son When she looks for 'puppy' in the 'Pets and Animals' category Then she should obtain a list of ads for puppies for sale.

search_by_keyword_and_location.story

1

Page 30: Bdd state-of-the-union

30

Scenario: Searching by keyword and location

Given Sally wants to buy a puppy for her son When she looks for 'puppy' in the 'Pets and Animals' category Then she should obtain a list of puppy ads

search_by_keyword_and_location.story

1

public class SearchAdsSteps {    @Steps    BuyerSteps buyer;

    @Given("Sally wants to buy a $present for her son")    public void buyingAPresent(String present) {        buyer.opens_home_page();    }

    @When("she looks for $keyword in the $category category")    public void adSearchByCategoryAndKeyword(String category, String keyword) {        buyer.chooses_category_and_keywords(category, keyword);        buyer.performs_search();    }

    @Then("she should obtain a list of $keyword ads")    public void shouldOnlySeeAdsContainingKeyword(String keyword) {        buyer.should_only_see_results_with_titles_containing(keyword);    }}

2

Page 31: Bdd state-of-the-union

31

Scenario: Searching by keyword and location

Given Sally wants to buy a puppy for her son When she looks for 'puppy' in the 'Pets and Animals' category Then she should obtain a list of puppy ads

search_by_keyword_and_location.story

1

public class SearchAdsSteps {    @Steps    BuyerSteps buyer;

    @Given("Sally wants to buy a $present for her son")    public void buyingAPresent(String present) {        buyer.opens_home_page();    }

    @When("she looks for $keyword in the $category category")    public void adSearchByCategoryAndKeyword(String category, String keyword) {        buyer.chooses_category_and_keywords(category, keyword);        buyer.performs_search();    }

    @Then("she should obtain a list of $keyword ads")    public void shouldOnlySeeAdsContainingKeyword(String keyword) {        buyer.should_only_see_results_with_titles_containing(keyword);    }}

2public class BuyerStories extends JUnitStories {    public BuyerStories() {        configuredEmbedder().embedderControls().doGenerateViewAfterStories(true).doIgnoreFailureInStories(false)                .doIgnoreFailureInView(true).doVerboseFailures(true).useThreads(2).useStoryTimeoutInSecs(60);    }

    @Override    public Configuration configuration() {        return new MostUsefulConfiguration();    }

    @Override    public InjectableStepsFactory stepsFactory() {        return new InstanceStepsFactory(configuration(), new TraderSteps(new TradingService()), new AndSteps());    }

    @Override    protected List<String> storyPaths() {        String codeLocation = codeLocationFromClass(this.getClass()).getFile();        return new StoryFinder().findPaths(codeLocation, asList("**/*.story",                "**/traders_can_be_subset.story"), asList(""), "file:" + codeLocation);    }}

3

Page 32: Bdd state-of-the-union

32

Scenario: Searching by keyword and location

Given Sally wants to buy a puppy for her son When she looks for 'puppy' in the 'Pets and Animals' category Then she should obtain a list of puppy ads

search_by_keyword_and_location.story

1

public class SearchAdsSteps {    @Steps    BuyerSteps buyer;

    @Given("Sally wants to buy a $present for her son")    public void buyingAPresent(String present) {        buyer.opens_home_page();    }

    @When("she looks for $keyword in the $category category")    public void adSearchByCategoryAndKeyword(String category, String keyword) {        buyer.chooses_category_and_keywords(category, keyword);        buyer.performs_search();    }

    @Then("she should obtain a list of $keyword ads")    public void shouldOnlySeeAdsContainingKeyword(String keyword) {        buyer.should_only_see_results_with_titles_containing(keyword);    }}

public class BuyerStories extends ThucydidesJUnitStories {}

3’

2

Page 33: Bdd state-of-the-union

33

Now available in JVM flavor!

Page 34: Bdd state-of-the-union

34

Feature:In order to increase sales of advertised articlesAs a sellerI want buyers to be able to easily find ads for articles they want to buy

Scenario: Searching by keyword and location

Given Sally wants to buy a "puppy" for her son When she looks for "puppy" in the "Pets and Animals" category Then she should obtain a list of "puppy" ads

1

Page 35: Bdd state-of-the-union

35

Scenario: Searching by keyword and location

Given Sally wants to buy a "puppy" for her son When she looks for "puppy" in the "Pets and Animals" category Then she should obtain a list of "puppy" ads

Scenario: Searching by keyword and location

Given Sally wants to buy a <present> for her son When she looks for '<present>' in the '<category>' category Then she should obtain a list of ads for <expected> for sale.

Examples:|present |category |expected||puppy |Pets & Animals | puppies||kitten |Pets & Animals | kittens||seiko |Jewellery & Watches| watch |

Page 36: Bdd state-of-the-union

36

Scenario: Searching by keyword and location

Given Sally wants to buy a "puppy" for her son When she looks for "puppy" in the "Pets and Animals" category Then she should obtain a list of "puppy" ads

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

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

1

2

Page 37: Bdd state-of-the-union

37

Scenario: Searching by keyword and location

Given Sally wants to buy a "puppy" for her son When she looks for "puppy" in the "Pets and Animals" category Then she should obtain a list of "puppy" ads

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

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

1

2public class SearchAdsSteps {    @Steps    BuyerSteps buyer;

    @Given("^Sally wants to buy a \"([^\"]*)\" for her son$")    public void buyingAPresent(String present) {        buyer.opens_home_page();    }

    @When("^she looks for \"([^\"]*)\" in the \"([^\"]*)\" category$")    public void adSearchByCategoryAndKeyword(String category, String keyword) {        buyer.chooses_category_and_keywords(category, keyword);        buyer.performs_search();    }

    @Then("^she should obtain a list of \"([^\"]*)\" ads$")    public void shouldOnlySeeAdsContainingKeyword(String keyword) {        buyer.should_only_see_results_with_titles_containing(keyword);    }}

3

Page 38: Bdd state-of-the-union

38

100% Groovy

Page 39: Bdd state-of-the-union

39

scenario "Searching by keyword and location", { given "Sally wants to buy a puppy for her son" when "she looks for 'puppy' in the 'Pets and Animals' category" then "she should obtain a list of ads for puppies for sale"}

search_by_keyword_and_location.story

scenario "Searching by keyword and location", { given "Sally wants to buy a #present for her son" when "she looks for '#present' in the '#category' category" then "she should obtain a list of ads for #expected for sale" where "examples should be", { present = ['puppy', 'kitten', 'seiko'] category = ['Pets & Animals','Pets & Animals', 'Jewellery & Watches'] expected = ['puppies', 'kittens', 'watch'] }}

Page 40: Bdd state-of-the-union

40

scenario "Searching by keyword and location", { given "Sally wants to buy a puppy for her son" when "she looks for 'puppy' in the 'Pets and Animals' category" then "she should obtain a list of ads for puppies for sale"}

search_by_keyword_and_location.story

1

Page 41: Bdd state-of-the-union

41

scenario "Searching by keyword and location", { given "Sally wants to buy a puppy for her son" when "she looks for 'puppy' in the 'Pets and Animals' category" then "she should obtain a list of ads for puppies for sale"}

search_by_keyword_and_location.story

1

using "thucydides"

thucydides.uses_steps_from BuyerSteps

scenario "Searching by keyword and location", { given "Sally wants to buy a puppy for her son", { buyer.opens_home_page() } when "she looks for 'puppy' in the 'Pets and Animals' category", { buyer.chooses_category_and_keywords(category, keyword); buyer.performs_search(); } then "she should obtain a list of ads for puppies for sale",{ buyer.should_only_see_results_with_titles_containing keyword }}

2

Page 42: Bdd state-of-the-union

42

Keeping an eye on things

Page 43: Bdd state-of-the-union

43

(Think “Two-CDs”)

Page 44: Bdd state-of-the-union

44

Scenario: Searching by keywordGiven Sally wants to buy a puppy for her sonWhen she looks for ads in the Pets & Animals category containing puppyThen she should obtain a list of ads for puppies for sale

Page 45: Bdd state-of-the-union

45

Scenario: Searching by keywordGiven Sally wants to buy a puppy for her sonWhen she looks for ads in the Pets & Animals category containing puppyThen she should obtain a list of ads for puppies for salepublic class SearchAdsSteps {

    @Steps    BuyerSteps buyer;

    @Given("Sally wants to buy a $present for her son")    public void buyingAPresent(String present) {        buyer.opens_home_page();    }

    @When("she looks for $keyword in the $category category")    public void adSearchByCategoryAndKeyword(String category, String keyword) {        buyer.chooses_category_and_keywords(category, keyword);        buyer.performs_search();    }

    @Then("she should obtain a list of $keyword ads")    public void shouldOnlySeeAdsContainingKeyword(String keyword) {        buyer.should_only_see_results_with_titles_containing(keyword);    }}

Page 46: Bdd state-of-the-union

46

public class SearchAdsSteps {    @Steps    BuyerSteps buyer;

    @Given("Sally wants to buy a $present for her son")    public void buyingAPresent(String present) {        buyer.opens_home_page();    }

    @When("she looks for $keyword in the $category category")    public void adSearchByCategoryAndKeyword(String category, String keyword) {        buyer.chooses_category_and_keywords(category, keyword);        buyer.performs_search();    }

    @Then("she should obtain a list of $keyword ads")    public void shouldOnlySeeAdsContainingKeyword(String keyword) {        buyer.should_only_see_results_with_titles_containing(keyword);    }}

public class BuyerSteps extends ScenarioSteps {

    HomePage homePage;    SearchResultsPage searchResultsPage;

    public BuyerSteps(Pages pages) {        super(pages);        homePage = getPages().get(HomePage.class);        searchResultsPage = getPages().get(SearchResultsPage.class);    }

    @Step    public void opens_home_page() {        homePage.open();    }

    @Step    public void chooses_region(String region) {        homePage.chooseRegion(region);    }

    @Step    public void chooses_category_and_keywords(String category, String keywords) {        homePage.chooseCategoryFromDropdown(category);        homePage.enterKeywords(keywords);    }

Page 47: Bdd state-of-the-union

47

Page 48: Bdd state-of-the-union

48

Page 49: Bdd state-of-the-union

49

Page 50: Bdd state-of-the-union

50

Page 51: Bdd state-of-the-union

51

Page 52: Bdd state-of-the-union

52

Page 53: Bdd state-of-the-union

From Acceptance Tests to Developer Tests

Page 54: Bdd state-of-the-union

BDD - A Development Tool

Page 55: Bdd state-of-the-union

TDD or BDD?

Page 56: Bdd state-of-the-union

Write a failing test

Make it pass

Refactor

TDD

What test should I write?

Page 57: Bdd state-of-the-union

Developer Tests (low level features)

Acceptance Tests (high level features)

etc.

Spock

What features should I implement?

Page 58: Bdd state-of-the-union

Story: In order to find the items I am interested in fasterAs a buyerI want to be able to list all the ads with a particular keyword in the description or title.

Goal: In order to increase revenue from commissions on classified ads salesAs the head of the classified ads departmentI want to increase the number of items sold via our classified ads

Scenario: Searching by keyword and locationGiven Sally wants to buy a puppy for her sonWhen she looks for ads in the Pets & Animals category containing puppy in New South Wales

Scenario: Searching by keyword and locationGiven Sally wants to buy a puppy for her sonWhen she looks for ads in the Pets & Animals category containing puppy in New South Wales

Scenario: Searching by keywordGiven Sally wants to buy a puppy for her sonWhen she looks for ads in the Pets & Animals category containing puppyThen she should obtain a list of ads for puppies for sale

Acceptance  Tests

Developer  Tests

class WhenCalculatingGST extends Specification {

    def "GST should apply on ordinary articles"() {        given: "we are selling a shirt"            def sale = Sale.of(1,"shirt").forANetPriceOf(10.00)        when: "we calculate the price including GST"            def totalPrice = sale.totalPrice        then: "the price should include GST of 10%"            totalPrice == 11.00    }}

class WhenCalculatingGST extends Specification {

    def "GST should apply on ordinary articles"() {        given: "we are selling a shirt"            def sale = Sale.of(1,"shirt").forANetPriceOf(10.00)        when: "we calculate the price including GST"            def totalPrice = sale.totalPrice        then: "the price should include GST of 10%"            totalPrice == 11.00    }}

class WhenCalculatingGST extends Specification {

    def "GST should apply on ordinary articles"() {        given: "we are selling a shirt"            def sale = Sale.of(1,"shirt").forANetPriceOf(10.00)        when: "we calculate the price including GST"            def totalPrice = sale.totalPrice        then: "the price should include GST of 10%"            totalPrice == 11.00    }}

Page 59: Bdd state-of-the-union

Unit Tests Acceptance tests

Page 60: Bdd state-of-the-union

Spock - BDD for developers

Page 61: Bdd state-of-the-union

Spockclass WhenCalculatingGST extends Specification {

    def "GST should apply on ordinary articles"() {        given: "we are selling a shirt"            def sale = Sale.of(1,"shirt").forANetPriceOf(10.00)        when: "we calculate the price including GST"            def totalPrice = sale.totalPrice        then: "the price should include GST of 10%"            totalPrice == 11.00    }}

Given-When-Then structure

Page 62: Bdd state-of-the-union

Spockclass WhenCalculatingGST extends Specification {

    ...

    def "GST should not apply on GST-exempt articles"() {        given: "we are selling a bottle of milk"          def sale = Sale.of(1,"shirt").forANetPriceOf(5.00)        when: "we calculate the price including GST"            def totalPrice = sale.totalPrice        then: "the price should not include GST%"            totalPrice == 5.00    }}

Meaningful error messages

Page 63: Bdd state-of-the-union

Spock

class WhenCalculatingGST extends Specification {

    def "GST should apply on ordinary articles"() {        given: "GST is at 12.5%"            def gstRateProvider = Mock(GSTRateProvider)            gstRateProvider.getRate() >> 0.125            Sales sales = new Sales(gstRateProvider)        and: "we are selling a shirt"            def sale = sales.makeSaleOf(1,"shirt").forANetPriceOf(10.00)        when: "we calculate the price including GST"            def totalPrice = sale.totalPrice        then: "the price should include GST of 12.5%"            totalPrice == 11.25    }}

Lightweight stubbing

Page 64: Bdd state-of-the-union

Spock

class WhenDeliveringSoldItems extends Specification {

    def gstRateProvider = Mock(GSTRateProvider)    def deliveryService = Mock(DeliveryService)

    def "Sold articles should be delivered"() {        given: "we are selling shirts online"            Sales sales = new Sales(gstRateProvider, deliveryService)        when: "we sell a shirt"            sales.makeSaleOf(1,"shirt").forANetPriceOf(10.00)        then: "the shirt should be sent to the delivery service"            1 * deliveryService.dispatch(_)    }}

Lightweight mocking

Page 65: Bdd state-of-the-union

class WhenDisplayingTagNamesInAReadableForm extends Specification {

    def inflection = Inflector.instance

    def "should transform singular nouns into plurals"() {

        when: "I find the plural form of a single word"            def pluralForm = inflection.of(singleForm).inPluralForm().toString();        then: "the plural form should be gramatically correct"            pluralForm == expectedPluralForm        where:            singleForm | expectedPluralForm            'epic' | 'epics'            'feature' | 'features'            'story' | 'stories'            'stories' | 'stories'            'octopus' | 'octopi'            'sheep' | 'sheep'    }}

Spock

Data-driven tests

Page 66: Bdd state-of-the-union

Spec2 - BDD for Scala

Page 67: Bdd state-of-the-union

class  WhenCalculatingGST  extends  Specification  {  sequential

   "GST  should  apply  on  ordinary  articles"  >>  {        "Given  we  are  selling  a  shirt"  >>  {            sale  =  Sale.of(1,  "shirt").forANetPriceOf(10.00)        }        "When  we  calculate  the  price  including  GST"  >>  {            totalPrice  =  sale.totalPrice        }        "Then  the  price  should  include  a  GST  of  10%"  >>  {            totalPrice  ===  11.00        }    }

   var  sale  =  Sale();  var  totalPrice  =  0.0}

Page 68: Bdd state-of-the-union

class  WhenCalculatingGST2  extends  Specification  with  Mockito  {  sequential

   "GST  should  apply  on  ordinary  articles"  >>  {        "Given  we  are  selling  a  shirt"  >>  {            val  sales  =  Sales(mock[GSTProvider])            sales.gstProvider.rate  returns  12.5

           sale  =  sales.makeSaleOf(1,  "shirt").forANetPriceOf(10.00)        }        "When  we  calculate  the  price  including  GST"  >>  {            totalPrice  =  sale.totalPrice        }        "Then  the  price  should  include  a  GST  of  12.5%"  >>  {            totalPrice  ===  11.25        }    }

   var  sale  =  Sale();  var  totalPrice  =  0.0}

Lightweight stubbing DSL

Page 69: Bdd state-of-the-union

class  WhenDeliveringSoldItems  extends  Specification  with  Mockito  {  sequential

   "Sold  articles  should  be  delivered"  >>  {        "Given  we  are  selling  shirts  online"  >>  {            sales  =  Sales(mock[GSTProvider],  mock[DeliveryService])        }        "When  we  sell  a  shirt"  >>  {            sale  =  sales.makeSaleOf(1,  "shirt").forANetPriceOf(10.00)        }        "Then  the  shirt  should  be  sent  to  the  delivery  service"  >>  {            there  was  one(sales.deliveryService).dispatch(anyString)        }    }

   var  sale  =  Sale();  var  sales  =  Sales()}

Lightweight mocking DSL

Page 70: Bdd state-of-the-union

class  WhenDisplayingTagNamesInAReadableForm  extends  Specification  with  Tables  {

   "The  inflector  should  transform  singular  nouns  into  plurals"  >>  {                                                                                                                                """        when  I  find  the  plural  form  of  a  single  word,  then  the  plural  form  should  be        gramatically  correct:                                                                                                                                """  >>  {            "single  form"    |  "plural  form"    |>            "epic"                  !  "epics"                |            "feature"            !  "features"          |            "story"                !  "story"                |            "stories"            !  "stories"            |            "octopus"            !  "octopi"              |            "sheep"                !  "sheep"                |  {  (singleForm,  pluralForm)  =>

               Inflection.of(singleForm).inPluralForm.toString  ===  pluralForm

           }        }    }}

Data-driven tests, Scala-style

Page 71: Bdd state-of-the-union

Jasmine - BDD for Javascript

Page 72: Bdd state-of-the-union

describe( "temperature converter", function () {     it("converts fahrenheit to celsius", function () {         expect(Convert(50, "F").to("C")).toEqual(10);     }); });

Simple assertion structure

Page 73: Bdd state-of-the-union

describe( "temperature converter", function () {     it("converts fahrenheit to celsius", function () {         expect(Convert(50, "F").to("C")).toEqual(10);     });       it("converts celsius to fahrenheit", function () {         expect(Convert(30, "C").to("F")).toEqual(86);     }); });

More complex behavior

Page 74: Bdd state-of-the-union

describe( "converter library", function () {     describe( "temperature converter", function () {         it("converts fahrenheit to celsius", function () {             expect(Convert(50, "F").to("C")).toEqual(10);         });           it("converts celsius to fahrenheit", function () {             expect(Convert(30, "C").to("F")).toEqual(86);         });     });

    describe( "weight converter", function () {         it("converts kilograms to pounds", function () {             expect(Convert(100, "KG").to("LB")).toEqual(220);         });     });});

Nested behaviors

Page 75: Bdd state-of-the-union

And it works with Maven!

Page 76: Bdd state-of-the-union

Evaluate test results in a browser

Page 77: Bdd state-of-the-union

Evaluate test results in a browser

Page 78: Bdd state-of-the-union

Generate JUnit-compatible results

Page 79: Bdd state-of-the-union

hAp://try-­‐jasmine.heroku.com/

Page 80: Bdd state-of-the-union

It’s behavior all the way down

In conclusion...

Page 81: Bdd state-of-the-union

Thank You

John  Ferguson  Smart