SlideShare uma empresa Scribd logo
1 de 81
Baixar para ler 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...
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.
Requirements can come from many sources...
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




Scenario: Searching by keyword
Given Sally wants to buy a puppy for her son
When she looks for ads in the Pets & Animals category containing puppy
Then she should obtain a list of ads for puppies for sale
45


Scenario: Searching by keyword
Given Sally wants to buy a puppy for her son
When she looks for ads in the Pets & Animals category containing puppy
Then she should obtain a list of ads for puppies for sale
  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);
       }
   }
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();
    }
           public class BuyerSteps extends ScenarioSteps {
    @When("she looks for $keyword in the $category category")
    public     HomePage homePage;
           void adSearchByCategoryAndKeyword(String category, String keyword) {
               SearchResultsPage searchResultsPage;
        buyer.chooses_category_and_keywords(category, keyword);
        buyer.performs_search();
               public BuyerSteps(Pages pages) {
    }              super(pages);
                   homePage = getPages().get(HomePage.class);
    @Then("she should obtain a list getPages().get(SearchResultsPage.class);
                   searchResultsPage = of $keyword ads")
    public     } shouldOnlySeeAdsContainingKeyword(String keyword) {
           void
        buyer.should_only_see_results_with_titles_containing(keyword);
    }          @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);
               }
47
48
49
50
51
52
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
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
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

Mais conteúdo relacionado

Semelhante a Bdd state-of-the-union

Google adwords-use-for-your-business
Google adwords-use-for-your-businessGoogle adwords-use-for-your-business
Google adwords-use-for-your-business
Dr,Saini Anand
 
Introduction to ad words
Introduction to ad wordsIntroduction to ad words
Introduction to ad words
Dr,Saini Anand
 
Creating awareness using modern media
Creating awareness using modern mediaCreating awareness using modern media
Creating awareness using modern media
MailerMailer
 
Content Marketing - Beyond the Bullshit
Content Marketing - Beyond the BullshitContent Marketing - Beyond the Bullshit
Content Marketing - Beyond the Bullshit
Hannah Smith
 

Semelhante a Bdd state-of-the-union (20)

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
 
Why do I need Content Marketing?
Why do I need Content Marketing? Why do I need Content Marketing?
Why do I need Content Marketing?
 
Advanced PPC for E-Commerce Websites
Advanced PPC for E-Commerce WebsitesAdvanced PPC for E-Commerce Websites
Advanced PPC for E-Commerce Websites
 
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
 
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
 
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
 
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
 
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 ...
 
Introduction to ad words
Introduction to ad wordsIntroduction to ad words
Introduction to ad words
 
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
 
Creating awareness using modern media
Creating awareness using modern mediaCreating awareness using modern media
Creating awareness using modern media
 
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
 
Content Marketing - Beyond the Bullshit
Content Marketing - Beyond the BullshitContent Marketing - Beyond the Bullshit
Content Marketing - Beyond the Bullshit
 
Copywriting -part_3
Copywriting  -part_3Copywriting  -part_3
Copywriting -part_3
 
Digital Marketing In Hyderabad
Digital Marketing In HyderabadDigital Marketing In Hyderabad
Digital Marketing In Hyderabad
 
Paid Search for E-commerce Marketing
Paid Search for E-commerce MarketingPaid Search for E-commerce Marketing
Paid Search for E-commerce Marketing
 

Mais de John Ferguson Smart Limited

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

  • 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. 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.
  • 24. Requirements can come from many sources...
  • 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 Scenario: Searching by keyword Given Sally wants to buy a puppy for her son When she looks for ads in the Pets & Animals category containing puppy Then she should obtain a list of ads for puppies for sale
  • 45. 45 Scenario: Searching by keyword Given Sally wants to buy a puppy for her son When she looks for ads in the Pets & Animals category containing puppy Then she should obtain a list of ads for puppies for sale 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);     } }
  • 46. 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();     } public class BuyerSteps extends ScenarioSteps {     @When("she looks for $keyword in the $category category")     public     HomePage homePage; void adSearchByCategoryAndKeyword(String category, String keyword) {     SearchResultsPage searchResultsPage;         buyer.chooses_category_and_keywords(category, keyword);         buyer.performs_search();     public BuyerSteps(Pages pages) {     }         super(pages);         homePage = getPages().get(HomePage.class);     @Then("she should obtain a list getPages().get(SearchResultsPage.class);         searchResultsPage = of $keyword ads")     public     } shouldOnlySeeAdsContainingKeyword(String keyword) { void         buyer.should_only_see_results_with_titles_containing(keyword);     }     @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);     }
  • 47. 47
  • 48. 48
  • 49. 49
  • 50. 50
  • 51. 51
  • 52. 52
  • 53. From Acceptance Tests to Developer Tests
  • 54. BDD - A Development Tool
  • 56. Make it pass Write a failing test TDD Refactor What test should I write?
  • 57. Acceptance Tests (high level features) Spock Developer Tests (low level features) What features should I implement? etc.
  • 58. 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 }     } }     } }
  • 59. Unit Tests Acceptance tests
  • 60. Spock - BDD for developers
  • 61. 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
  • 62. 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
  • 63. 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     } }
  • 64. 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
  • 65. 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
  • 66. Spec2 - BDD for Scala
  • 67. 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 }
  • 68. 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 }
  • 69. 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 }
  • 70. 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            }        }    } }
  • 71. Jasmine - BDD for Javascript
  • 72. describe( "temperature converter", function () {     it("converts fahrenheit to celsius", function () {         expect(Convert(50, "F").to("C")).toEqual(10);     }); }); Simple assertion structure
  • 73. 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
  • 74. 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
  • 75. And it works with Maven!
  • 76. Evaluate test results in a browser
  • 77. Evaluate test results in a browser
  • 81. Thank You John  Ferguson  Smart