SlideShare a Scribd company logo
1 of 90
Download to read offline
Behavior-Driven Development on the JVM
          A State of the Union




                              John	
  Ferguson	
  Smart
Consulta
                    nt
            Trainer
           Mentor
           Author
          Speaker
          Coder
John Fer
         guson S
                 mar t
What is BDD?
Business Analyst




           Common
           Language
Business                      Developer




              Tester
Executable
Specifications
Ou
  ts
    id
       e
           In
Value Driven
So why use BDD?
Only build features that add real value
Less wasted effort
Better communication
Higher quality, better tested product
Traceability
BDD - Requirements Analysis and
        Communication
Goals

   Capabilities

     Features

      Stories


Examples/Scenarios


Acceptance Criteria
11


 Successful projects start with a shared vision


“We are going to build an online classifieds website”
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.”
Determining the value of a goal

   A good goal should add value to the business
    Increase revenue
    Reduce costs
    Avoid future costs
    Protect revenue


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

 Why?
                     So that our sellers can sell their stuff faster
  Why?
                  So that they keep selling their stuff on our site
   Why?

So that we keep earning money when they post their ads with us
What does the customer really need?

  Good teams push back!
   Users tend to express requirements as implementations
   We 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 sellers
    Buyers 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
Features and capabilities help deliver these goals



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

                    Notify potential buyers about new items
                    In Search for online of advertised articles
                       order to increase sales ads
                    As aorder to increase sales of advertised articles
                     In seller
                    I want previous buyers to know about new items
                      As a seller
                    that theybuyers be interested in buying ads for
                      I want might to be able to easily find
                     articles they want to buy
Feature Injection - what features do you do first?

  Our goals say what business value we need to deliver
  We implement the minimum features required to
  deliver this business value
    Search for online ads                              The goal comes first
   In order to increase sales of advertised articles
                                                          The stakeholder is
   As a seller                                               secondary
   I want buyers to be able to easily find ads for
   articles they want to buy
                                                    The feature must be
                                                 required to achieve the goal
18


We use examples and stories to explore the features




Search for online ads




“Searching by category”

   “Searching by keyword and category”
19


We use examples and stories to explore the features




Search for online ads




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


Examples and scenarios become acceptance criteria

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.

           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 Keywords
                        puppy                         Pets & Animals                           labrador
                         kitten                       Pets & Animals                           burmese
                         kitten                              Toys                              fluffy cat




     Acceptance Criteria illustrate and validate the stories
Organize your requirements
Requirements can come from many sources...
Requirements can come from many sources...
Goal:
In order to increase revenue from commissions on classified ads sales
As the head of the classified ads department
I want to increase the number of items sold via our classified ads

           Capability
           In order to increase the number of items I sell       Feature

           As a seller                                           In order to increase sales of advertised articles

           I want buyers to be able to view ads for items        As a seller

           they might want to purchase                           I want potential buyers to be able to display only the ads for
                                                                 articles that they might be interested in purchasing.




                                                                 Story
                                                                 In order to find the items I am interested in faster
     Keep them organized!                                        As a buyer
                                                                 I want to be able to list all the ads with a particular keyword in
                                                                 the description or title.
25




BDD - Test Automation and Beyond
26




The original Java BDD framework
27



search_by_keyword_and_location.story
 Narrative:
 In order to increase sales of advertised articles
 As a seller
 I 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.
28



search_by_keyword_and_location.story
 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.


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



search_by_keyword_and_location.story
 Scenario: Searching by keyword and location                     1
 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.
30



search_by_keyword_and_location.story
 Scenario: Searching by keyword and location                                       1
 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
 public class SearchAdsSteps {
     @Steps
                                                                              2
     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);
     }
 }
31



search_by_keyword_and_location.story
 Scenario: Searching by keyword and location                                                                 1
 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
 public class SearchAdsSteps {
     @Steps
                                                                                                    2
     BuyerSteps buyer;

   public class BuyerStories extends JUnitStories {
     @Given("Sally wants to buy a $present for her son")
       public BuyerStories() {
     public void buyingAPresent(String present) {
                                                                                                               3
           configuredEmbedder().embedderControls().doGenerateViewAfterStories(true).doIgnoreFailureInStories(false)
         buyer.opens_home_page();
                   .doIgnoreFailureInView(true).doVerboseFailures(true).useThreads(2).useStoryTimeoutInSecs(60);
       }
     }
       @Override
     @When("she looks for $keyword { the $category category")
       public Configuration configuration() in
     public void adSearchByCategoryAndKeyword(String category, String keyword) {
           return new MostUsefulConfiguration();
       }
         buyer.chooses_category_and_keywords(category, keyword);
         buyer.performs_search();
       @Override
     }
       public InjectableStepsFactory stepsFactory() {
           return new InstanceStepsFactory(configuration(), new TraderSteps(new TradingService()), new AndSteps());
       }
     @Then("she should obtain a list of $keyword ads")
     public void shouldOnlySeeAdsContainingKeyword(String keyword) {
       @Override
         buyer.should_only_see_results_with_titles_containing(keyword);
       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);
       }
   }
32



search_by_keyword_and_location.story
 Scenario: Searching by keyword and location                                       1
 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
 public class SearchAdsSteps {
     @Steps
                                                                              2
     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);
     }

                                                                                   3’
 }
          public class BuyerStories extends ThucydidesJUnitStories {
          }
33




Now available in JVM flavor!
34




Feature:                                                             1
In order to increase sales of advertised articles
As a seller
I 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
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 |
36




Scenario: Searching by keyword and location                     1
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;                          2
import cucumber.junit.Cucumber;

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




Scenario: Searching by keyword and location                                         1
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;                                       2
import cucumber.junit.Cucumber;
  public class SearchAdsSteps {
      @Steps
@RunWith(Cucumber.class)
                                                                              3
      BuyerSteps buyer;
@Cucumber.Options(format={"pretty", "html:target/cucumber"})
public class RunTests { buy a "([^"]*)" for her son$")
      @Given("^Sally wants to
}     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);
      }
  }
38




100% Groovy
39



search_by_keyword_and_location.story
 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"
 }


   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']
       }
   }
40



search_by_keyword_and_location.story
 scenario "Searching by keyword and location", {                       1
     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"
 }
41



search_by_keyword_and_location.story
 scenario "Searching by keyword and location", {                       1
     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"
 }

  using "thucydides"                                                   2
  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
      }
  }
42




Keeping an eye on things
43




(Think “Two-CDs”)
44




1   Discover your acceptance criteria



    2   Automate your acceptance criteria



        3   Implement your acceptance criteria



            4   Execute your acceptance tests
45




        1        Discover your acceptance criteria

Feature: Browse Catalog
In order to find items that I would like to buy
As a customer
I want to be able to browse through the catalog

     Story: Browse by category
     In order to find items more easily
     As a customer
     I want to be able to browse through the product categories
          Acceptance Criteria
              See all the top-level categories
              Browse through the category hierarchy
              Should display the correct products for each category
              Each category should have the correct sub-categories



          Define acceptance criteria for each story
46




                               1     Discover your acceptance criteria


Acceptance Criteria
  See all the top-level categories
  Browse through the category hierarchy
  Should display the correct products for each category
  Each category should have the correct sub-categories

   Scenario: See all top-level categories
   Given I want to browse the catalog
   When I am on the home page
   Then I should see the following product categories: Clothing, Accessories, Shoes




                     Clarify the acceptance criteria with examples
47




(Do this together)
48




                       2       Automate your acceptance criteria


  Story: Browse by category
  In order to find items more easily
     Acceptance Criteria
  As a customer top-level categories
        See all the
  I want Browse through the category the product categories
         to be able to browse through hierarchy
      Scenario: See all top-level categories
        Should display the correct products for each category
      Given I want to browse the catalog
        Each category should have the correct sub-categories
      When I am on the home page
      Then I should see the following product categories: Clothing, Accessories, Shoes
Narrative:
In order to find items more easily
As a customer
I want to be able to see what product categories exist

Scenario: See all top-level categories
Given I want to browse the catalog
When I am on the home page
Then I should see the following product categories: Clothing, Accessories, Shoes


                   We now have an executable requirement
49




 2   Automate your acceptance criteria




...but they will be reported as ‘pending’
50




           3    Implement your acceptance criteria

Narrative:
In order to find items more easily
As a customer
I want to be able to see what product categories exist

Scenario: See all top-level categories
Given I want to browse the catalog
When I am on the home page
Then I should see the following product categories: Clothing, Accessories, Shoes
51




3   Implement your acceptance criteria
52




3   Implement your acceptance criteria




                                         JUnit
53




4   Execute your acceptance tests
54
55
56
57
58
59
From Acceptance Tests
  to Developer Tests
BDD - A Development Tool
TDD or BDD?
Make it pass




Write a failing test           TDD


                                                   Refactor



                       What test should I write?
Acceptance Tests
       (high level features)




                                                        Spock


                                                      Developer Tests
                                                    (low level features)



                    What features should I implement?
etc.
Goal: In order to increase revenue from commissions on classified ads sales
As the head of the classified ads department
I want to increase the number of items sold via our classified ads

     Story: In order to find the items I am interested in faster
                                                                                                    Acceptance	
  
     As a buyer
     I want to be able to list all the ads with a particular keyword in the description or title.         Tests

             Scenario: Searching by keyword and location
             Scenario: Searching by keyword and location
              Scenario: Searching by keyword
             Given Sally wants to buy a apuppyfor her son
             Given Sally wants to buy apuppy for her son
              Given Sally wants to buy puppy for her son
             When she looks for ads ininthePets & Animals category containing puppy
             When she looks for ads inthe Pets & Animals category containing puppy
              When she looks for ads the Pets & Animals category containing puppy
             inThen she should obtain a list of ads for puppies for sale
              inNew South Wales
                New South Wales



                class WhenCalculatingGST extends Specification {
                  class WhenCalculatingGST extends Specification {
                    class WhenCalculatingGST extends Specification {
                    def "GST should apply on ordinary articles"() {
                        given: should apply on ordinary articles"() { {
                      def "GST "we are selling a shirt"
                          given: should apply on ordinary articles"()
                        def "GST "we are selling a shirt"

                                                                                                     Developer	
  
                            def sale = Sale.of(1,"shirt").forANetPriceOf(10.00)
                              def sale areSale.of(1,"shirt").forANetPriceOf(10.00)
                            given: "we = selling a shirt"
                        when: "we calculate the price including GST"
                                def sale = Sale.of(1,"shirt").forANetPriceOf(10.00)
                            def "we calculate sale.totalPrice
                          when: totalPrice = the price including GST"
                              def "we calculate the price GST of
                            when: totalPrice               including GST"
                        then: "the totalPrice= =sale.totalPrice 10%"
                                def  price should sale.totalPrice
                                                   include
                            totalPrice == should include GST of 10%"
                          then: "the price 11.00 include GST of 10%"
                            then: "the price should
                              totalPrice == 11.00
                                                                                                          Tests
                    }
                                totalPrice == 11.00
                }     }
                  }     }
                    }
Unit Tests   Acceptance tests
Spock - BDD for developers
Spock
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
    }
}

                                   Given-When-Then structure
Spock
class 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
Spock
                          Lightweight stubbing
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
    }
}
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
Spock
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'
    }
}

                                                             Data-driven tests
Spock with Arquillian
class	
  AccountServiceSpecification	
  extends	
  Specification	
  {

	
  	
  	
  	
  @Deployment
	
  	
  	
  	
  def	
  static	
  JavaArchive	
  "create	
  deployment"()	
  {
	
  	
  	
  	
  	
  	
  	
  	
  return	
  ShrinkWrap.create(JavaArchive.class)
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  .addClasses(AccountService.class,	
  Account.class,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  SecureAccountService.class)
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  .addAsManifestResource(EmptyAsset.INSTANCE,	
  "beans.xml");
	
  	
  	
  	
  }

	
  	
  	
  	
  @Inject
	
  	
  	
  	
  AccountService	
  service

	
  	
  	
  	
  def	
  "transferring	
  between	
  accounts	
  should	
  result	
  in	
  account	
  withdrawl	
  and	
  deposit"()	
  {
	
  	
  	
  	
  	
  	
  	
  	
  when:
	
  	
  	
  	
  	
  	
  	
  	
  service.transfer(from,	
  to,	
  amount)

	
  	
  	
  	
  	
  	
  	
  	
  then:                                                                                                BDD-style integration tests
	
  	
  	
  	
  	
  	
  	
  	
  from.balance	
  ==	
  fromBalance
	
  	
  	
  	
  	
  	
  	
  	
  to.balance	
  ==	
  toBalance

	
  	
  	
  	
  	
  	
  	
  	
  where:
	
  	
  	
  	
  	
  	
  	
  	
  from	
  <<	
  	
  	
  	
  	
  	
  	
  	
  	
  [new	
  Account(100),	
  	
  new	
  Account(10)]
	
  	
  	
  	
  	
  	
  	
  	
  to	
  <<	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  [new	
  Account(50),	
  	
  	
  new	
  Account(90)]
	
  	
  	
  	
  	
  	
  	
  	
  amount	
  <<	
  	
  	
  	
  	
  	
  	
  [50,	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  10]
	
  	
  	
  	
  	
  	
  	
  	
  fromBalance	
  <<	
  	
  [50,	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  0]
	
  	
  	
  	
  	
  	
  	
  	
  toBalance	
  <<	
  	
  	
  	
  [100,	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  100]
	
  	
  	
  	
  }
}
Spec2 - BDD for Scala
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
}
class	
  WhenCalculatingGST2	
  extends	
  Specification	
  with	
  Mockito	
  
{	
  sequential

	
  	
  "GST	
  should	
  apply	
  on	
  ordinary	
  articles"	
  >>	
  {          Lightweight
	
  	
  	
  	
  "Given	
  we	
  are	
  selling	
  a	
  shirt"	
  >>	
  {          stubbing DSL
	
  	
  	
  	
  	
  	
  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
}
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)
	
  	
  	
  	
  }
	
  	
  }
                                                                                       Lightweight
	
  	
  var	
  sale	
  =	
  Sale();	
  var	
  sales	
  =	
  Sales()                   mocking DSL
}
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"	
  	
  	
  	
  	
  |                                                                                                                                                                   Data-driven tests,
	
  	
  	
  	
  	
  	
  "story"	
  	
  	
  	
  	
  	
  	
  	
  !	
  "story"	
  	
  	
  	
  	
  	
  	
  	
  |                                                                                                                                                           Scala-style
	
  	
  	
  	
  	
  	
  "stories"	
  	
  	
  	
  	
  	
  !	
  "stories"	
  	
  	
  	
  	
  	
  |
	
  	
  	
  	
  	
  	
  "octopus"	
  	
  	
  	
  	
  	
  !	
  "octopi"	
  	
  	
  	
  	
  	
  	
  |
	
  	
  	
  	
  	
  	
  "sheep"	
  	
  	
  	
  	
  	
  	
  	
  !	
  "sheep"	
  	
  	
  	
  	
  	
  	
  	
  |	
  {	
  (singleForm,	
  pluralForm)	
  =>

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

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

                              Simple assertion structure
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
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
Lots of matchers


it("is	
  defined",	
  function	
  ()	
  {	
  	
  
	
  	
  	
  	
  var	
  name	
  =	
  "Andrew";	
  	
           property defined
	
  	
  	
  	
  expect(name).toBeDefined();	
  	
  
})	
  	
  

 it("is	
  true",	
  function	
  ()	
  {	
  	
                                    true or false
 	
  	
  	
  	
  expect(Lib.isAWeekDay()).toBeTruthy();	
  	
  
 });	
  

    it("is	
  less	
  than	
  10",	
  function	
  ()	
  {	
  	
  
    	
  	
  	
  	
  expect(5).toBeLessThan(10);	
  	
                greater   than or less than
    });	
  	
  
    it("is	
  greater	
  than	
  10",	
  function	
  ()	
  {	
  	
  
    	
  	
  	
  	
  expect(20).toBeGreaterThan(10);	
  	
  
    });	
  

      it("should	
  contain	
  oranges",	
  function	
  ()	
  {	
  	
  
      	
  	
  	
  	
  expect(["apples",	
  "oranges",	
  "pears"]).toContain("oranges");	
  	
  
      });	
  
                                                                                      contains
And it works with Maven!
Evaluate test results in a browser
Evaluate test results in a browser
Generate JUnit-compatible results
hAp://try-­‐jasmine.heroku.com/
In conclusion...




It’s behavior all
the way down
Thank You




            John	
  Ferguson	
  Smart

More Related Content

Similar to Bdd state-of-the-union (Devoxx and XPDays version)

Functional testing the_good_the_bad_and_the_ugly
Functional testing the_good_the_bad_and_the_uglyFunctional testing the_good_the_bad_and_the_ugly
Functional testing the_good_the_bad_and_the_uglyJohn Ferguson Smart Limited
 
BOOST YOUR BUSINESS: (11) using inventory knowledge to close mo…
BOOST YOUR BUSINESS: (11) using inventory knowledge to close mo…BOOST YOUR BUSINESS: (11) using inventory knowledge to close mo…
BOOST YOUR BUSINESS: (11) using inventory knowledge to close mo…Michael McKenna
 
Google adwords-use-for-your-business
Google adwords-use-for-your-businessGoogle adwords-use-for-your-business
Google adwords-use-for-your-businessDr,Saini Anand
 
How to Win the War of Words on the Web
How to Win the War of Words on the WebHow to Win the War of Words on the Web
How to Win the War of Words on the WebWriterAccess
 
Advanced PPC for E-Commerce Websites
Advanced PPC for E-Commerce WebsitesAdvanced PPC for E-Commerce Websites
Advanced PPC for E-Commerce WebsitesJeff Sauer
 
Solutions Before Development: Creating WordPress Products That Actually Sell
Solutions Before Development: Creating WordPress Products That Actually SellSolutions Before Development: Creating WordPress Products That Actually Sell
Solutions Before Development: Creating WordPress Products That Actually SellRebecca Gill
 
How to Gain Customers and Increase Sales by Running Daily and Group Deals
How to Gain Customers and Increase Sales by Running Daily and Group DealsHow to Gain Customers and Increase Sales by Running Daily and Group Deals
How to Gain Customers and Increase Sales by Running Daily and Group Deals3dcart shopping cart software
 
Analyzing Queries to Find Revenue Opportunities
Analyzing Queries to Find Revenue OpportunitiesAnalyzing Queries to Find Revenue Opportunities
Analyzing Queries to Find Revenue OpportunitiesBill Hunt
 
SEO proposal - free template - SEOmonitor.com
SEO proposal - free template - SEOmonitor.comSEO proposal - free template - SEOmonitor.com
SEO proposal - free template - SEOmonitor.comMadalina-Carla Mihai
 
Customer and Competitive Conversation and Analysis
Customer and Competitive Conversation and AnalysisCustomer and Competitive Conversation and Analysis
Customer and Competitive Conversation and AnalysisgShift
 
Introduction to ad words
Introduction to ad wordsIntroduction to ad words
Introduction to ad wordsDr,Saini Anand
 
ConversionWorks at the How to be Social event
ConversionWorks at the How to be Social eventConversionWorks at the How to be Social event
ConversionWorks at the How to be Social eventConversionWorks
 
VA lecture 2.pptx
VA lecture 2.pptxVA lecture 2.pptx
VA lecture 2.pptxRidaBabar4
 
Copywriting -part_3
Copywriting  -part_3Copywriting  -part_3
Copywriting -part_3MOMOBACHIR
 
Digital Demand from Click to Close: Realigning Search Marketing for the B2B ...
Digital Demand from Click to Close:  Realigning Search Marketing for the B2B ...Digital Demand from Click to Close:  Realigning Search Marketing for the B2B ...
Digital Demand from Click to Close: Realigning Search Marketing for the B2B ...DemandWave
 

Similar to Bdd state-of-the-union (Devoxx and XPDays version) (20)

Functional testing the_good_the_bad_and_the_ugly
Functional testing the_good_the_bad_and_the_uglyFunctional testing the_good_the_bad_and_the_ugly
Functional testing the_good_the_bad_and_the_ugly
 
To atdd-and-beyond
To atdd-and-beyondTo atdd-and-beyond
To atdd-and-beyond
 
BOOST YOUR BUSINESS: (11) using inventory knowledge to close mo…
BOOST YOUR BUSINESS: (11) using inventory knowledge to close mo…BOOST YOUR BUSINESS: (11) using inventory knowledge to close mo…
BOOST YOUR BUSINESS: (11) using inventory knowledge to close mo…
 
Google adwords-use-for-your-business
Google adwords-use-for-your-businessGoogle adwords-use-for-your-business
Google adwords-use-for-your-business
 
How to Win the War of Words on the Web
How to Win the War of Words on the WebHow to Win the War of Words on the Web
How to Win the War of Words on the Web
 
PLR CASH COURSE
PLR CASH COURSEPLR CASH COURSE
PLR CASH COURSE
 
Advanced PPC for E-Commerce Websites
Advanced PPC for E-Commerce WebsitesAdvanced PPC for E-Commerce Websites
Advanced PPC for E-Commerce Websites
 
Why do I need Content Marketing?
Why do I need Content Marketing? Why do I need Content Marketing?
Why do I need Content Marketing?
 
Solutions Before Development: Creating WordPress Products That Actually Sell
Solutions Before Development: Creating WordPress Products That Actually SellSolutions Before Development: Creating WordPress Products That Actually Sell
Solutions Before Development: Creating WordPress Products That Actually Sell
 
How to Gain Customers and Increase Sales by Running Daily and Group Deals
How to Gain Customers and Increase Sales by Running Daily and Group DealsHow to Gain Customers and Increase Sales by Running Daily and Group Deals
How to Gain Customers and Increase Sales by Running Daily and Group Deals
 
Analyzing Queries to Find Revenue Opportunities
Analyzing Queries to Find Revenue OpportunitiesAnalyzing Queries to Find Revenue Opportunities
Analyzing Queries to Find Revenue Opportunities
 
SEO proposal - free template - SEOmonitor.com
SEO proposal - free template - SEOmonitor.comSEO proposal - free template - SEOmonitor.com
SEO proposal - free template - SEOmonitor.com
 
Webinar: Unlocking the Power of Your AdWords Search Query Report
Webinar: Unlocking the Power of Your AdWords Search Query ReportWebinar: Unlocking the Power of Your AdWords Search Query Report
Webinar: Unlocking the Power of Your AdWords Search Query Report
 
Topic Documentation
Topic Documentation Topic Documentation
Topic Documentation
 
Customer and Competitive Conversation and Analysis
Customer and Competitive Conversation and AnalysisCustomer and Competitive Conversation and Analysis
Customer and Competitive Conversation and Analysis
 
Introduction to ad words
Introduction to ad wordsIntroduction to ad words
Introduction to ad words
 
ConversionWorks at the How to be Social event
ConversionWorks at the How to be Social eventConversionWorks at the How to be Social event
ConversionWorks at the How to be Social event
 
VA lecture 2.pptx
VA lecture 2.pptxVA lecture 2.pptx
VA lecture 2.pptx
 
Copywriting -part_3
Copywriting  -part_3Copywriting  -part_3
Copywriting -part_3
 
Digital Demand from Click to Close: Realigning Search Marketing for the B2B ...
Digital Demand from Click to Close:  Realigning Search Marketing for the B2B ...Digital Demand from Click to Close:  Realigning Search Marketing for the B2B ...
Digital Demand from Click to Close: Realigning Search Marketing for the B2B ...
 

More from John Ferguson Smart Limited

My Reading Specs - Refactoring Patterns for Gherkin Scenarios
My Reading Specs - Refactoring Patterns for Gherkin ScenariosMy Reading Specs - Refactoring Patterns for Gherkin Scenarios
My Reading Specs - Refactoring Patterns for Gherkin ScenariosJohn Ferguson Smart Limited
 
Artisti e Condotierri - How can your team become artists of the 21st century ...
Artisti e Condotierri - How can your team become artists of the 21st century ...Artisti e Condotierri - How can your team become artists of the 21st century ...
Artisti e Condotierri - How can your team become artists of the 21st century ...John Ferguson Smart Limited
 
Engage! Bringing teams together to deliver software that makes a difference
Engage! Bringing teams together to deliver software that makes a differenceEngage! Bringing teams together to deliver software that makes a difference
Engage! Bringing teams together to deliver software that makes a differenceJohn Ferguson Smart Limited
 
Sustainable Test Automation with Serenity BDD and Screenplay
Sustainable Test Automation with Serenity BDD and ScreenplaySustainable Test Automation with Serenity BDD and Screenplay
Sustainable Test Automation with Serenity BDD and ScreenplayJohn Ferguson Smart Limited
 
Engage! Bringing teams together to deliver software that makes a difference
Engage! Bringing teams together to deliver software that makes a differenceEngage! Bringing teams together to deliver software that makes a difference
Engage! Bringing teams together to deliver software that makes a differenceJohn Ferguson Smart Limited
 
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...John Ferguson Smart Limited
 
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...John Ferguson Smart Limited
 
Screenplay - Next generation automated acceptance testing
Screenplay - Next generation automated acceptance testingScreenplay - Next generation automated acceptance testing
Screenplay - Next generation automated acceptance testingJohn Ferguson Smart Limited
 
All the world's a stage – the next step in automated testing practices
All the world's a stage – the next step in automated testing practicesAll the world's a stage – the next step in automated testing practices
All the world's a stage – the next step in automated testing practicesJohn Ferguson Smart Limited
 
It's Testing, Jim, but not as we know it - BDD for Testers
It's Testing, Jim, but not as we know it - BDD for TestersIt's Testing, Jim, but not as we know it - BDD for Testers
It's Testing, Jim, but not as we know it - BDD for TestersJohn Ferguson Smart Limited
 

More from John Ferguson Smart Limited (20)

My Reading Specs - Refactoring Patterns for Gherkin Scenarios
My Reading Specs - Refactoring Patterns for Gherkin ScenariosMy Reading Specs - Refactoring Patterns for Gherkin Scenarios
My Reading Specs - Refactoring Patterns for Gherkin Scenarios
 
Artisti e Condotierri - How can your team become artists of the 21st century ...
Artisti e Condotierri - How can your team become artists of the 21st century ...Artisti e Condotierri - How can your team become artists of the 21st century ...
Artisti e Condotierri - How can your team become artists of the 21st century ...
 
Engage! Bringing teams together to deliver software that makes a difference
Engage! Bringing teams together to deliver software that makes a differenceEngage! Bringing teams together to deliver software that makes a difference
Engage! Bringing teams together to deliver software that makes a difference
 
BE A POD OF DOLPHINS, NOT A DANCING ELEPHANT
BE A POD OF DOLPHINS, NOT A DANCING ELEPHANTBE A POD OF DOLPHINS, NOT A DANCING ELEPHANT
BE A POD OF DOLPHINS, NOT A DANCING ELEPHANT
 
Sustainable Test Automation with Serenity BDD and Screenplay
Sustainable Test Automation with Serenity BDD and ScreenplaySustainable Test Automation with Serenity BDD and Screenplay
Sustainable Test Automation with Serenity BDD and Screenplay
 
Feature Mapping Workshop
Feature Mapping WorkshopFeature Mapping Workshop
Feature Mapping Workshop
 
Engage! Bringing teams together to deliver software that makes a difference
Engage! Bringing teams together to deliver software that makes a differenceEngage! Bringing teams together to deliver software that makes a difference
Engage! Bringing teams together to deliver software that makes a difference
 
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...
 
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...
 
Shift left-devoxx-pl
Shift left-devoxx-plShift left-devoxx-pl
Shift left-devoxx-pl
 
Screenplay - Next generation automated acceptance testing
Screenplay - Next generation automated acceptance testingScreenplay - Next generation automated acceptance testing
Screenplay - Next generation automated acceptance testing
 
Cucumber and Spock Primer
Cucumber and Spock PrimerCucumber and Spock Primer
Cucumber and Spock Primer
 
All the world's a stage – the next step in automated testing practices
All the world's a stage – the next step in automated testing practicesAll the world's a stage – the next step in automated testing practices
All the world's a stage – the next step in automated testing practices
 
CukeUp 2016 Agile Product Planning Workshop
CukeUp 2016 Agile Product Planning WorkshopCukeUp 2016 Agile Product Planning Workshop
CukeUp 2016 Agile Product Planning Workshop
 
BDD Anti-patterns
BDD Anti-patternsBDD Anti-patterns
BDD Anti-patterns
 
Serenity and the Journey Pattern
Serenity and the Journey PatternSerenity and the Journey Pattern
Serenity and the Journey Pattern
 
BDD - Collaborate like you mean it!
BDD - Collaborate like you mean it!BDD - Collaborate like you mean it!
BDD - Collaborate like you mean it!
 
BDD-Driven Microservices
BDD-Driven MicroservicesBDD-Driven Microservices
BDD-Driven Microservices
 
BDD Anti-patterns
BDD Anti-patternsBDD Anti-patterns
BDD Anti-patterns
 
It's Testing, Jim, but not as we know it - BDD for Testers
It's Testing, Jim, but not as we know it - BDD for TestersIt's Testing, Jim, but not as we know it - BDD for Testers
It's Testing, Jim, but not as we know it - BDD for Testers
 

Bdd state-of-the-union (Devoxx and XPDays version)

  • 1. Behavior-Driven Development on the JVM A State of the Union John  Ferguson  Smart
  • 2. Consulta nt Trainer Mentor Author Speaker Coder John Fer guson S mar t
  • 4. Business Analyst Common Language Business Developer Tester
  • 6. Ou ts id e In
  • 8. So why use BDD? Only build features that add real value Less wasted effort Better communication Higher quality, better tested product Traceability
  • 9. BDD - Requirements Analysis and Communication
  • 10. Goals Capabilities Features Stories Examples/Scenarios Acceptance Criteria
  • 11. 11 Successful projects start with a shared vision “We are going to build an online classifieds website”
  • 12. 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.”
  • 13. Determining the value of a goal A good goal should add value to the business Increase revenue Reduce costs Avoid future costs Protect revenue “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”
  • 14. 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 Why? So that our sellers can sell their stuff faster Why? So that they keep selling their stuff on our site Why? So that we keep earning money when they post their ads with us
  • 15. What does the customer really need? Good teams push back! Users tend to express requirements as implementations We 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 sellers Buyers 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
  • 16. Features and capabilities help deliver these goals “Let’s get more sales for our advertisers by making the ads easier to find online.” Notify potential buyers about new items In Search for online of advertised articles order to increase sales ads As aorder to increase sales of advertised articles In seller I want previous buyers to know about new items As a seller that theybuyers be interested in buying ads for I want might to be able to easily find articles they want to buy
  • 17. Feature Injection - what features do you do first? Our goals say what business value we need to deliver We implement the minimum features required to deliver this business value Search for online ads The goal comes first In order to increase sales of advertised articles The stakeholder is As a seller secondary I want buyers to be able to easily find ads for articles they want to buy The feature must be required to achieve the goal
  • 18. 18 We use examples and stories to explore the features Search for online ads “Searching by category” “Searching by keyword and category”
  • 19. 19 We use examples and stories to explore the features Search for online ads 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.
  • 20. 20 Examples and scenarios become acceptance criteria 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. 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 Keywords puppy Pets & Animals labrador kitten Pets & Animals burmese kitten Toys fluffy cat Acceptance Criteria illustrate and validate the stories
  • 22. Requirements can come from many sources...
  • 23. Requirements can come from many sources...
  • 24. Goal: In order to increase revenue from commissions on classified ads sales As the head of the classified ads department I want to increase the number of items sold via our classified ads Capability In order to increase the number of items I sell Feature As a seller In order to increase sales of advertised articles I want buyers to be able to view ads for items As a seller they might want to purchase I want potential buyers to be able to display only the ads for articles that they might be interested in purchasing. Story In order to find the items I am interested in faster Keep them organized! As a buyer I want to be able to list all the ads with a particular keyword in the description or title.
  • 25. 25 BDD - Test Automation and Beyond
  • 26. 26 The original Java BDD framework
  • 27. 27 search_by_keyword_and_location.story Narrative: In order to increase sales of advertised articles As a seller I 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.
  • 28. 28 search_by_keyword_and_location.story 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. 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 |
  • 29. 29 search_by_keyword_and_location.story Scenario: Searching by keyword and location 1 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.
  • 30. 30 search_by_keyword_and_location.story Scenario: Searching by keyword and location 1 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 public class SearchAdsSteps {     @Steps 2     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);     } }
  • 31. 31 search_by_keyword_and_location.story Scenario: Searching by keyword and location 1 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 public class SearchAdsSteps {     @Steps 2     BuyerSteps buyer; public class BuyerStories extends JUnitStories {     @Given("Sally wants to buy a $present for her son")     public BuyerStories() {     public void buyingAPresent(String present) { 3         configuredEmbedder().embedderControls().doGenerateViewAfterStories(true).doIgnoreFailureInStories(false)         buyer.opens_home_page();                 .doIgnoreFailureInView(true).doVerboseFailures(true).useThreads(2).useStoryTimeoutInSecs(60);     }     }     @Override     @When("she looks for $keyword { the $category category")     public Configuration configuration() in     public void adSearchByCategoryAndKeyword(String category, String keyword) {         return new MostUsefulConfiguration();     }         buyer.chooses_category_and_keywords(category, keyword);         buyer.performs_search();     @Override     }     public InjectableStepsFactory stepsFactory() {         return new InstanceStepsFactory(configuration(), new TraderSteps(new TradingService()), new AndSteps());     }     @Then("she should obtain a list of $keyword ads")     public void shouldOnlySeeAdsContainingKeyword(String keyword) {     @Override         buyer.should_only_see_results_with_titles_containing(keyword);     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);     } }
  • 32. 32 search_by_keyword_and_location.story Scenario: Searching by keyword and location 1 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 public class SearchAdsSteps {     @Steps 2     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);     } 3’ } public class BuyerStories extends ThucydidesJUnitStories { }
  • 33. 33 Now available in JVM flavor!
  • 34. 34 Feature: 1 In order to increase sales of advertised articles As a seller I 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
  • 35. 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 |
  • 36. 36 Scenario: Searching by keyword and location 1 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; 2 import cucumber.junit.Cucumber; @RunWith(Cucumber.class) @Cucumber.Options(format={"pretty", "html:target/cucumber"}) public class RunTests { }
  • 37. 37 Scenario: Searching by keyword and location 1 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; 2 import cucumber.junit.Cucumber; public class SearchAdsSteps {     @Steps @RunWith(Cucumber.class) 3     BuyerSteps buyer; @Cucumber.Options(format={"pretty", "html:target/cucumber"}) public class RunTests { buy a "([^"]*)" for her son$")     @Given("^Sally wants to }     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);     } }
  • 39. 39 search_by_keyword_and_location.story 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" } 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'] } }
  • 40. 40 search_by_keyword_and_location.story scenario "Searching by keyword and location", { 1 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" }
  • 41. 41 search_by_keyword_and_location.story scenario "Searching by keyword and location", { 1 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" } using "thucydides" 2 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 } }
  • 42. 42 Keeping an eye on things
  • 44. 44 1 Discover your acceptance criteria 2 Automate your acceptance criteria 3 Implement your acceptance criteria 4 Execute your acceptance tests
  • 45. 45 1 Discover your acceptance criteria Feature: Browse Catalog In order to find items that I would like to buy As a customer I want to be able to browse through the catalog Story: Browse by category In order to find items more easily As a customer I want to be able to browse through the product categories Acceptance Criteria See all the top-level categories Browse through the category hierarchy Should display the correct products for each category Each category should have the correct sub-categories Define acceptance criteria for each story
  • 46. 46 1 Discover your acceptance criteria Acceptance Criteria See all the top-level categories Browse through the category hierarchy Should display the correct products for each category Each category should have the correct sub-categories Scenario: See all top-level categories Given I want to browse the catalog When I am on the home page Then I should see the following product categories: Clothing, Accessories, Shoes Clarify the acceptance criteria with examples
  • 48. 48 2 Automate your acceptance criteria Story: Browse by category In order to find items more easily Acceptance Criteria As a customer top-level categories See all the I want Browse through the category the product categories to be able to browse through hierarchy Scenario: See all top-level categories Should display the correct products for each category Given I want to browse the catalog Each category should have the correct sub-categories When I am on the home page Then I should see the following product categories: Clothing, Accessories, Shoes Narrative: In order to find items more easily As a customer I want to be able to see what product categories exist Scenario: See all top-level categories Given I want to browse the catalog When I am on the home page Then I should see the following product categories: Clothing, Accessories, Shoes We now have an executable requirement
  • 49. 49 2 Automate your acceptance criteria ...but they will be reported as ‘pending’
  • 50. 50 3 Implement your acceptance criteria Narrative: In order to find items more easily As a customer I want to be able to see what product categories exist Scenario: See all top-level categories Given I want to browse the catalog When I am on the home page Then I should see the following product categories: Clothing, Accessories, Shoes
  • 51. 51 3 Implement your acceptance criteria
  • 52. 52 3 Implement your acceptance criteria JUnit
  • 53. 53 4 Execute your acceptance tests
  • 54. 54
  • 55. 55
  • 56. 56
  • 57. 57
  • 58. 58
  • 59. 59
  • 60. From Acceptance Tests to Developer Tests
  • 61. BDD - A Development Tool
  • 63. Make it pass Write a failing test TDD Refactor What test should I write?
  • 64. Acceptance Tests (high level features) Spock Developer Tests (low level features) What features should I implement? etc.
  • 65. Goal: In order to increase revenue from commissions on classified ads sales As the head of the classified ads department I want to increase the number of items sold via our classified ads Story: In order to find the items I am interested in faster Acceptance   As a buyer I want to be able to list all the ads with a particular keyword in the description or title. Tests Scenario: Searching by keyword and location Scenario: Searching by keyword and location Scenario: Searching by keyword Given Sally wants to buy a apuppyfor her son Given Sally wants to buy apuppy for her son Given Sally wants to buy puppy for her son When she looks for ads ininthePets & Animals category containing puppy When she looks for ads inthe Pets & Animals category containing puppy When she looks for ads the Pets & Animals category containing puppy inThen she should obtain a list of ads for puppies for sale inNew South Wales New South Wales class WhenCalculatingGST extends Specification { class WhenCalculatingGST extends Specification { class WhenCalculatingGST extends Specification {     def "GST should apply on ordinary articles"() {         given: should apply on ordinary articles"() { {     def "GST "we are selling a shirt"         given: should apply on ordinary articles"()     def "GST "we are selling a shirt" Developer               def sale = Sale.of(1,"shirt").forANetPriceOf(10.00)             def sale areSale.of(1,"shirt").forANetPriceOf(10.00)         given: "we = selling a shirt"         when: "we calculate the price including GST"             def sale = Sale.of(1,"shirt").forANetPriceOf(10.00)             def "we calculate sale.totalPrice         when: totalPrice = the price including GST"             def "we calculate the price GST of         when: totalPrice including GST"         then: "the totalPrice= =sale.totalPrice 10%"             def price should sale.totalPrice include             totalPrice == should include GST of 10%"         then: "the price 11.00 include GST of 10%"         then: "the price should             totalPrice == 11.00 Tests     }             totalPrice == 11.00 }     } }     } }
  • 66. Unit Tests Acceptance tests
  • 67. Spock - BDD for developers
  • 68. Spock 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     } } Given-When-Then structure
  • 69. Spock class 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
  • 70. Spock Lightweight stubbing 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     } }
  • 71. 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
  • 72. Spock 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'     } } Data-driven tests
  • 73. Spock with Arquillian class  AccountServiceSpecification  extends  Specification  {        @Deployment        def  static  JavaArchive  "create  deployment"()  {                return  ShrinkWrap.create(JavaArchive.class)                                                  .addClasses(AccountService.class,  Account.class,                                                                            SecureAccountService.class)                                                  .addAsManifestResource(EmptyAsset.INSTANCE,  "beans.xml");        }        @Inject        AccountService  service        def  "transferring  between  accounts  should  result  in  account  withdrawl  and  deposit"()  {                when:                service.transfer(from,  to,  amount)                then: BDD-style integration tests                from.balance  ==  fromBalance                to.balance  ==  toBalance                where:                from  <<                  [new  Account(100),    new  Account(10)]                to  <<                      [new  Account(50),      new  Account(90)]                amount  <<              [50,                                10]                fromBalance  <<    [50,                                0]                toBalance  <<        [100,                              100]        } }
  • 74. Spec2 - BDD for Scala
  • 75. 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 }
  • 76. class  WhenCalculatingGST2  extends  Specification  with  Mockito   {  sequential    "GST  should  apply  on  ordinary  articles"  >>  { Lightweight        "Given  we  are  selling  a  shirt"  >>  { stubbing DSL            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 }
  • 77. 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)        }    } Lightweight    var  sale  =  Sale();  var  sales  =  Sales() mocking DSL }
  • 78. 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"          | Data-driven tests,            "story"                !  "story"                | Scala-style            "stories"            !  "stories"            |            "octopus"            !  "octopi"              |            "sheep"                !  "sheep"                |  {  (singleForm,  pluralForm)  =>                Inflection.of(singleForm).inPluralForm.toString  ===  pluralForm            }        }    } }
  • 79. Jasmine - BDD for Javascript
  • 80. describe( "temperature converter", function () {     it("converts fahrenheit to celsius", function () {         expect(Convert(50, "F").to("C")).toEqual(10);     }); }); Simple assertion structure
  • 81. 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
  • 82. 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
  • 83. Lots of matchers it("is  defined",  function  ()  {            var  name  =  "Andrew";     property defined        expect(name).toBeDefined();     })     it("is  true",  function  ()  {     true or false        expect(Lib.isAWeekDay()).toBeTruthy();     });   it("is  less  than  10",  function  ()  {            expect(5).toBeLessThan(10);     greater than or less than });     it("is  greater  than  10",  function  ()  {            expect(20).toBeGreaterThan(10);     });   it("should  contain  oranges",  function  ()  {            expect(["apples",  "oranges",  "pears"]).toContain("oranges");     });   contains
  • 84. And it works with Maven!
  • 85. Evaluate test results in a browser
  • 86. Evaluate test results in a browser
  • 90. Thank You John  Ferguson  Smart