Acceptance Test Driven Development
Bringing Testers and Developers Together




                         John Ferguson Smart
                         Wakaleo Consulting Ltd.
                         http://www.wakaleo.com
                         Email: john.smart@wakaleo.com
                         Twitter: wakaleo
Introduction
So what’s this talk about, anyway
 Acceptance tests as a communication tool
 Acceptance Test Driven Development
 BDD-style Acceptance Tests - easyb
Acceptance Tests
Acceptance Tests - a key Agile practice
 A communication tool
 Owned by the customer
 Determine when a feature is ‘done’
 Written together (customer, developer, tester)
 Focus on What, not How
Acceptance Tests
Acceptance Tests - how far do you go?
 In depth tests or examples of system usage?
 Exhaustive Tests or Sample Stories?
Acceptance Tests
Acceptance Tests - a key Agile practice
     User Story 1 - Transfer funds
   User Story 11- -Calculate my tax rate
    User Story      Calculate my tax rate
As a bank client, I want to transfer funds from
my current account to my savings account, so
 As a tax payer, I want to be able to calculate my
that I a taxearn more interest able to calculate my
  As can payer, I want to be
 tax online, so that I can put enough money aside.
  tax online, so that I can put enough money aside.



            So how do we know when
              this feature is done?
Acceptance Tests
Acceptance Tests - a key Agile practice

    User Story 11- ---Acceptance Testsrate
     User Story 11Calculate my tax
      User Story      Transfer funds
     User Story      Calculate my tax rate
- As a bank client,money between two accounts from
  Client can transfer I want to transfer funds
- my current account to my savings account, so
  Client can’t transfer negative amount
- Client can’t transfer wantthan currentto calculate my
   As a tax payer, I more to be able account balance
  that I a taxearn more interest able to calculate my
    As can payer, I want to be
- Client can’t transfer from a blocked accountmoney aside.
   tax online, so that I can put enough
   tax online, so that I can put enough money aside.



               So how do we know when
                 this feature is done?


                                  Let’s write some
                                 Acceptance Criteria
Acceptance Tests
Acceptance Criteria
 Conditions that must be met before the story is complete
 Provided by the customer
 Some folks use a more formal notation
 How do I get my tests? Just add some examples!




                              User Story 1 - Acceptance Tests
                       - Client can transfer money between two accounts
                       - Client can’t transfer negative amount
                       - Client can’t transfer more than current account balance
                       - Client can’t transfer from a blocked account
Acceptance Test-Driven Development
Acceptance Tests drive work during the iteration




                            Pick a story card
                            Write the acceptance tests
                            Automate the acceptance tests
                            Implement the user story


 Iteration n-1       Iteration n                   Iteration n+1
Acceptance Test-Driven Development
Implementing/Automating the Acceptance Tests
 Acceptance Tests become ‘executable’
 Focus is still on communication
 You don’t need to use the same language as the application
Tools for the job
What tools exist? Two main approaches
 Narrative
  easyb, JBehave, rspec, Cucumber,...
 Table-based
  Fitnesse,...
Introducing easyb
So what is easyb, anyway?
 A BDD testing framework for Java
 Make testing clearer and easier to write
 Make tests self-documenting
 Help developers focus on the requirements
 Based on Groovy
 Java-like syntax
 Quick to write
 Full access to Java classes and APIs
 Well-suited to Acceptance Tests




                                             BDD Acceptance Testing
Easyb in Action
Easyb supports Specifications and Stories
 Specifications express requirements as simple statements
 Stories use the “given-when-then” approach
Easyb Specifications
Writing Easyb Specifications
 Simple and informal
 Easy to write
 Very similar to acceptance criteria
Easyb Specifications
Writing Easyb Specifications
      User Story 1 - Acceptance Tests
- Client can transfer money between two accounts
- Client can’t transfer negative amount
- Client can’t transfer more than current account balance
- Client can’t transfer from a blocked account

                                                            Start off with our acceptance criteria
    AccountTransfer.specifications

     description "A client should be able to transfer money between accounts"

     it   "should   let   a client transfer   money from a current to a savings a/c"
     it   "should   not   allow a client to   transfer a negative amount"
     it   "should   not   allow a client to   transfer more than the current balance"
     it   "should   not   allow a client to   transfer from a blocked account"



                                               Express these in Easyb
Easyb Specifications
Writing Easyb Specifications
 Executable Requirements

 description "A client should be able to transfer money between accounts"

 it   "should   let   a client transfer   money from a current to a savings a/c"
 it   "should   not   allow a client to   transfer a negative amount"
 it   "should   not   allow a client to   transfer more than the current balance"
 it   "should   not   allow a client to   transfer from a blocked account"

                                                                      This code will run!




                                               The tests are marked as ‘PENDING’
Easyb Specifications
Writing Easyb Specifications
 HTML Progress reports
Easyb Specifications
 Writing Easyb Specifications
  Implementing the tests
   package com.wakaleo.accounts.domain

   description "A client should be able to transfer money between accounts"

   it   "should let a client transfer money from a current to a savings a/c", {
   	     current = new Account(200)
   	     savings = new Account(300)           A developer implements the test in Groovy
   	
   	     current.transferTo(savings, 50)
   	
   	     savings.balance.shouldBe 350
   	     current.balance.shouldBe 150
   }
   it   "should not allow a client to transfer a negative amount"
   it   "should not allow a client to transfer more than the current balance"
   it   "should not allow a client to transfer from a blocked account"




No longer pending


  Still pending...
Easyb Stories
Writing Easyb Stories
 Use a narrative approach
 Describe a precise requirement
 Can be understood by a stakeholder
 Usually made up of a set of scenarios
 Use an easy-to-understand structure:
   Given [a context]...
   When [something happens]...
   Then [something else happens]...
Easyb Stories
Building an easyb story
 A story is made up of scenarios
 Scenarios validate specific behaviour

       User Story 1 - Acceptance Tests
 - Client can transfer money between two accounts
 - Client can’t transfer negative amount
 - Client can’t transfer more than current account balance
 - Client can’t transfer from a blocked account


  AccountTransfer.story

  scenario   "A   client   can transfer money from a current to a savings a/c"
  scenario   "A   client   is not allowed to transfer a negative amount"
  scenario   "A   client   is not allowed to transfer more than the current balance"
  scenario   "A   client   is not allowed to transfer from a blocked account"
Easyb Stories
Anatomy of an easyb story
scenario "A client can transfer money from a current to a savings a/c", {
	 given 'a current a/c with $200 and a savings a/c with $300'
	 when 'you transfer $50 from the current a/c to the savings a/c'
	 then 'the savings a/c should have $350 and the current a/c $150'
}

 “Scenario”: corresponds to precise requirement
 “Given”: the context in which this requirement applies
 “When”: An event or action
 “Then”: The expected results of this action
Easyb Stories
Implementing the scenario
 package com.wakaleo.accounts.domain

 scenario "A client can transfer money from a current to a savings a/c", {
 	 given 'a current a/c with $200 and a savings a/c with $300', {
 	 	 current = new Account(200)
 	 	 savings = new Account(300)	  	 	 	
 	 }
 	 when 'you transfer $50 from the current a/c to the savings a/c', {
 	 	 current.transferTo(savings, 50)	 	
 	 }
 	 then 'the savings a/c should have $350 and the current a/c $150', {
 	 	 savings.balance.shouldBe 350
 	 	 current.balance.shouldBe 150
 	 }	 	 	
 }

 scenario "A client is not allowed to transfer a negative amount"
 scenario "A client is not allowed to transfer more than the current balance"
 scenario "A client is not allowed to transfer from a blocked account"
Easyb Stories
Implementing the scenario - an alternative solution
 package com.wakaleo.accounts.domain

 scenario "A client can transfer money from a current to a savings a/c", {
 	 given 'a current a/c with $200', {
 	 	 current = new Account(200)                    Using ‘and’ for more clarity
 	 }
 	 and 'a savings a/c with $300', {
 	 	 savings = new Account(300)	  	 	 	
     }
     when 'you transfer $50 from the current a/c to the savings a/c', {
 	 	 current.transferTo(savings, 50)	 	
 	 }
 	 then 'the savings a/c should have $350', {
 	 	 savings.balance.shouldBe 350
 	 }
 	 and 'the current a/c should have $150', {
 	 	 current.balance.shouldBe 150
 	 }
 }
 scenario "A client is not allowed to transfer a negative amount"
 scenario "A client is not allowed to transfer more than the current balance"
 scenario "A client is not allowed to transfer from a blocked account"
Easyb assertions
Ensuring what should be
 The shouldBe syntax:
 Intuitive, readable and flexible
  account.balance.shouldBe initialAmount

 Comes in many flavors
  account.balance.shouldBeEqualTo initialAmount


  account.balance.shouldNotBe 0


   account.balance.shouldBeGreaterThan 0


    account.shouldHave(balance:initialAmount)
Easyb Stories
Implementing another scenario - error conditions
package com.wakaleo.accounts.domain

scenario "A client can transfer money from a current to a savings a/c", {
   ...
}
scenario "A client is not allowed to transfer a negative amount", {
	   given 'a current a/c with $200', {
	   	   current = new Account(200)
	   }
	   and 'a savings a/c with $300', {
	   	   savings = new Account(300)		  	   	
	   }
	   when "you try to transfer a negative amount", {              Create a closure
	   	   transferNegativeAmount = {                         representing this operation
	   	   	   current.transferTo(savings, -50)
	   	   }
	   }
	   then "an IllegalTransferException should be thrown", {
	   	   ensureThrows(IllegalTransferException.class) {
	   	   	   transferNegativeAmount()                         Fail if the exception is not
	   	   }                                                               thrown
	   }
}
scenario "A client is not allowed to transfer more than the current balance"
scenario "A client is not allowed to transfer from a blocked account"
Easyb fixtures
Structuring your tests...fixtures in easyb
 Setting up the test environment...
  Similar to JUnit fixtures @Before and @BeforeClass
  before is run at the start of the whole story
  before_each is run before each scenario
  Useful for setting up databases, test servers, etc.
Easyb fixtures
Refactoring our scenarios - before and before_each
before_each "setup the test accounts", {
	    given 'a current a/c with $200', {
	    	    current = new Account(200)                       This will be done before
	    }
	    and 'a savings a/c with $300', {
                                                                each scenario
	    	    savings = new Account(300)	 	  	    	
	    }
}

scenario "A client can transfer money from a current to a savings a/c", {
     when 'you transfer $50 from the current a/c to the savings a/c', {
	    	    current.transferTo(savings, 50)	 	
	    }
	    then 'the savings a/c should have $350 and the current a/c $150', {
	    	    savings.balance.shouldBe 350
	    }
	    and 'the current a/c should have $150', {
	    	    current.balance.shouldBe 150
	    }
}

scenario "A client is not allowed to transfer a negative amount", {
	    when "you try to transfer a negative amount", {
	    	    transferNegativeAmount = {
	    	    	    current.transferTo(savings, -50)
	    	    }
	    }
	    then "an IllegalTransferException should be thrown", {
	    	    ensureThrows(IllegalTransferException.class) {
	    	    	    transferNegativeAmount()
	    	    }
	    }
}
Easyb fixtures
Shared behaviour
 Refactor common code in easyb scenarios
 shared_behavior "shared behaviors", {
   given "a string", {
     var = ""                                     Common behavior (‘shared_behavior’)
   }
   when "the string is hello world", {
     var = "hello world"
   }
 }

 scenario "first scenario", {
   it_behaves_as "shared behaviors"
  
   then "the string should start with hello", {       Reused here (‘it_behaves_as’)...
     var.shouldStartWith "hello"
   }
 }

 scenario "second scenario", {
   it_behaves_as "shared behaviors"
  
   then "the string should end with world", {           ...and here
     var.shouldEndWith "world"
   }
 }
Web testing with easyb
Easyb is convenient for web testing
 BDD/Functional tests
 Run against a test server, or use Jetty
 Use your choice of web testing frameworks
  Selenium
  JWebUnit
  ...
Web testing with easyb
Many options - let’s look at two
 Selenium
 Runs in a browser
 High-level API
 Runs slower and more work to set up
 JWebUnit
 Simulates a browser
 Runs faster, easy to set up
 API slightly lower level
Web testing with easyb
An example - writing functional tests with JWebUnit
import net.sourceforge.jwebunit.junit.WebTester

before_each "initialize a web test client", {                Set up a JWebUnit client
  given "we have a web test client", {
	   tester = new WebTester()
	   tester.setBaseUrl("http://localhost:8080/tweeter-web")
  }
}

scenario "User signup should add a new user", {
	
	   when "I click on the sign up button on the home page", {
	   	    tester.beginAt("/home")                                      Click on a link
	   	    tester.clickLinkWithText("Sign up now!")
	   }
	   and "I enter a new username and password", {
	   	    tester.setTextField("username", "jane")                 Enter some values
	   	    tester.setTextField("password", "tiger")
	   	    tester.submit()
	   }
	   then "the application should log me on as the new user and show a welcome message", {
	   	    tester.assertTextPresent("Hi jane!")
	   }                                                          Check the results
}
Easyb reports
The easyb HTML report




                        Test results summary

                           Unimplemented stories



                               Failed stories
Easyb reports
The easyb HTML report

                        Test results summary




                          Test failure details




                         Unimplemented stories
Other Approaches
How does easyb compare with other tools?
 Cucumber, RSpec (Ruby) - very similar to easyb
 FitNesse - wikis and tables
 Concordion - marked-up HTML
FitNesse
FitNesse - wiki-based acceptance tests
 Test data is written at tables on a Wiki
 Java classes implement the tests behind the scenes
FitNesse
FitNesse - wiki-based acceptance tests
                    Test data and scenarios as a table




                Test data                           Expected results
FitNesse
FitNesse - wiki-based acceptance tests




                       Testers can write/edit the Wiki pages




                    You can also import to and from Excel
FitNesse
    FitNesse - wiki-based acceptance tests
                              public class TransferMoneyBetweenAccounts {
Tests are implemented by      	   private BigDecimal savingsBalance;
      Java classes            	   private BigDecimal currentBalance;
                              	   private BigDecimal transfer;
                              	   private BigDecimal finalSavingsBalance;
    Each column has a         	   private BigDecimal finalCurrentBalance;
                              	   private boolean exceptionThrown;
     field in the class
                              	
                              	   public void setSavingsBalance(BigDecimal savingsBalance) {...}
                              	   public void setCurrentBalance(BigDecimal currentBalance) {...}
                              	   public void setTransfer(BigDecimal transfer) {...}
                                  public BigDecimal finalCurrentBalance() {...}
   Expected results have      	   public BigDecimal finalSavingsBalance() {...}
          getters             	   public boolean exceptionThrown() {...}

                              	   public void execute() {
                              	   	   Account currentAccount = new Account(currentBalance);
                              	   	   Account savingsAccount = new Account(savingsBalance);
                              	   	
                              	   	   exceptionThrown = false;
                              	   	   try {
                              	   	   	   currentAccount.transferTo(savingsAccount, transfer);
        Performing the test   	   	   	   finalCurrentBalance = currentAccount.getBalance();
                              	   	   	   finalSavingsBalance = savingsAccount.getBalance();
                              	   	   } catch (IllegalTransferException e) {
                              	   	   	   exceptionThrown = true;
                              	   	   }
                                  }
Commercial options?
There are also some commercial tools out there...
 GreenPepper
  Supports tables and BDD-style
  Nice tool integration (Confluence, Maven,...)
 Twixt
  Thoughtworks product, focus on web testing
 Others?
Thank You



     John Ferguson Smart
     Wakaleo Consulting Ltd.
     http://www.wakaleo.com
     Email: john.smart@wakaleo.com
     Twitter: wakaleo

Acceptance Test Driven Development

  • 1.
    Acceptance Test DrivenDevelopment Bringing Testers and Developers Together John Ferguson Smart Wakaleo Consulting Ltd. http://www.wakaleo.com Email: john.smart@wakaleo.com Twitter: wakaleo
  • 2.
    Introduction So what’s thistalk about, anyway Acceptance tests as a communication tool Acceptance Test Driven Development BDD-style Acceptance Tests - easyb
  • 3.
    Acceptance Tests Acceptance Tests- a key Agile practice A communication tool Owned by the customer Determine when a feature is ‘done’ Written together (customer, developer, tester) Focus on What, not How
  • 4.
    Acceptance Tests Acceptance Tests- how far do you go? In depth tests or examples of system usage? Exhaustive Tests or Sample Stories?
  • 5.
    Acceptance Tests Acceptance Tests- a key Agile practice User Story 1 - Transfer funds User Story 11- -Calculate my tax rate User Story Calculate my tax rate As a bank client, I want to transfer funds from my current account to my savings account, so As a tax payer, I want to be able to calculate my that I a taxearn more interest able to calculate my As can payer, I want to be tax online, so that I can put enough money aside. tax online, so that I can put enough money aside. So how do we know when this feature is done?
  • 6.
    Acceptance Tests Acceptance Tests- a key Agile practice User Story 11- ---Acceptance Testsrate User Story 11Calculate my tax User Story Transfer funds User Story Calculate my tax rate - As a bank client,money between two accounts from Client can transfer I want to transfer funds - my current account to my savings account, so Client can’t transfer negative amount - Client can’t transfer wantthan currentto calculate my As a tax payer, I more to be able account balance that I a taxearn more interest able to calculate my As can payer, I want to be - Client can’t transfer from a blocked accountmoney aside. tax online, so that I can put enough tax online, so that I can put enough money aside. So how do we know when this feature is done? Let’s write some Acceptance Criteria
  • 7.
    Acceptance Tests Acceptance Criteria Conditions that must be met before the story is complete Provided by the customer Some folks use a more formal notation How do I get my tests? Just add some examples! User Story 1 - Acceptance Tests - Client can transfer money between two accounts - Client can’t transfer negative amount - Client can’t transfer more than current account balance - Client can’t transfer from a blocked account
  • 8.
    Acceptance Test-Driven Development AcceptanceTests drive work during the iteration Pick a story card Write the acceptance tests Automate the acceptance tests Implement the user story Iteration n-1 Iteration n Iteration n+1
  • 9.
    Acceptance Test-Driven Development Implementing/Automatingthe Acceptance Tests Acceptance Tests become ‘executable’ Focus is still on communication You don’t need to use the same language as the application
  • 10.
    Tools for thejob What tools exist? Two main approaches Narrative easyb, JBehave, rspec, Cucumber,... Table-based Fitnesse,...
  • 11.
    Introducing easyb So whatis easyb, anyway? A BDD testing framework for Java Make testing clearer and easier to write Make tests self-documenting Help developers focus on the requirements Based on Groovy Java-like syntax Quick to write Full access to Java classes and APIs Well-suited to Acceptance Tests BDD Acceptance Testing
  • 12.
    Easyb in Action Easybsupports Specifications and Stories Specifications express requirements as simple statements Stories use the “given-when-then” approach
  • 13.
    Easyb Specifications Writing EasybSpecifications Simple and informal Easy to write Very similar to acceptance criteria
  • 14.
    Easyb Specifications Writing EasybSpecifications User Story 1 - Acceptance Tests - Client can transfer money between two accounts - Client can’t transfer negative amount - Client can’t transfer more than current account balance - Client can’t transfer from a blocked account Start off with our acceptance criteria AccountTransfer.specifications description "A client should be able to transfer money between accounts" it "should let a client transfer money from a current to a savings a/c" it "should not allow a client to transfer a negative amount" it "should not allow a client to transfer more than the current balance" it "should not allow a client to transfer from a blocked account" Express these in Easyb
  • 15.
    Easyb Specifications Writing EasybSpecifications Executable Requirements description "A client should be able to transfer money between accounts" it "should let a client transfer money from a current to a savings a/c" it "should not allow a client to transfer a negative amount" it "should not allow a client to transfer more than the current balance" it "should not allow a client to transfer from a blocked account" This code will run! The tests are marked as ‘PENDING’
  • 16.
    Easyb Specifications Writing EasybSpecifications HTML Progress reports
  • 17.
    Easyb Specifications WritingEasyb Specifications Implementing the tests package com.wakaleo.accounts.domain description "A client should be able to transfer money between accounts" it "should let a client transfer money from a current to a savings a/c", { current = new Account(200) savings = new Account(300) A developer implements the test in Groovy current.transferTo(savings, 50) savings.balance.shouldBe 350 current.balance.shouldBe 150 } it "should not allow a client to transfer a negative amount" it "should not allow a client to transfer more than the current balance" it "should not allow a client to transfer from a blocked account" No longer pending Still pending...
  • 18.
    Easyb Stories Writing EasybStories Use a narrative approach Describe a precise requirement Can be understood by a stakeholder Usually made up of a set of scenarios Use an easy-to-understand structure: Given [a context]... When [something happens]... Then [something else happens]...
  • 19.
    Easyb Stories Building aneasyb story A story is made up of scenarios Scenarios validate specific behaviour User Story 1 - Acceptance Tests - Client can transfer money between two accounts - Client can’t transfer negative amount - Client can’t transfer more than current account balance - Client can’t transfer from a blocked account AccountTransfer.story scenario "A client can transfer money from a current to a savings a/c" scenario "A client is not allowed to transfer a negative amount" scenario "A client is not allowed to transfer more than the current balance" scenario "A client is not allowed to transfer from a blocked account"
  • 20.
    Easyb Stories Anatomy ofan easyb story scenario "A client can transfer money from a current to a savings a/c", { given 'a current a/c with $200 and a savings a/c with $300' when 'you transfer $50 from the current a/c to the savings a/c' then 'the savings a/c should have $350 and the current a/c $150' } “Scenario”: corresponds to precise requirement “Given”: the context in which this requirement applies “When”: An event or action “Then”: The expected results of this action
  • 21.
    Easyb Stories Implementing thescenario package com.wakaleo.accounts.domain scenario "A client can transfer money from a current to a savings a/c", { given 'a current a/c with $200 and a savings a/c with $300', { current = new Account(200) savings = new Account(300) } when 'you transfer $50 from the current a/c to the savings a/c', { current.transferTo(savings, 50) } then 'the savings a/c should have $350 and the current a/c $150', { savings.balance.shouldBe 350 current.balance.shouldBe 150 } } scenario "A client is not allowed to transfer a negative amount" scenario "A client is not allowed to transfer more than the current balance" scenario "A client is not allowed to transfer from a blocked account"
  • 22.
    Easyb Stories Implementing thescenario - an alternative solution package com.wakaleo.accounts.domain scenario "A client can transfer money from a current to a savings a/c", { given 'a current a/c with $200', { current = new Account(200) Using ‘and’ for more clarity } and 'a savings a/c with $300', { savings = new Account(300) } when 'you transfer $50 from the current a/c to the savings a/c', { current.transferTo(savings, 50) } then 'the savings a/c should have $350', { savings.balance.shouldBe 350 } and 'the current a/c should have $150', { current.balance.shouldBe 150 } } scenario "A client is not allowed to transfer a negative amount" scenario "A client is not allowed to transfer more than the current balance" scenario "A client is not allowed to transfer from a blocked account"
  • 23.
    Easyb assertions Ensuring whatshould be The shouldBe syntax: Intuitive, readable and flexible account.balance.shouldBe initialAmount Comes in many flavors account.balance.shouldBeEqualTo initialAmount account.balance.shouldNotBe 0 account.balance.shouldBeGreaterThan 0 account.shouldHave(balance:initialAmount)
  • 24.
    Easyb Stories Implementing anotherscenario - error conditions package com.wakaleo.accounts.domain scenario "A client can transfer money from a current to a savings a/c", { ... } scenario "A client is not allowed to transfer a negative amount", { given 'a current a/c with $200', { current = new Account(200) } and 'a savings a/c with $300', { savings = new Account(300) } when "you try to transfer a negative amount", { Create a closure transferNegativeAmount = { representing this operation current.transferTo(savings, -50) } } then "an IllegalTransferException should be thrown", { ensureThrows(IllegalTransferException.class) { transferNegativeAmount() Fail if the exception is not } thrown } } scenario "A client is not allowed to transfer more than the current balance" scenario "A client is not allowed to transfer from a blocked account"
  • 25.
    Easyb fixtures Structuring yourtests...fixtures in easyb Setting up the test environment... Similar to JUnit fixtures @Before and @BeforeClass before is run at the start of the whole story before_each is run before each scenario Useful for setting up databases, test servers, etc.
  • 26.
    Easyb fixtures Refactoring ourscenarios - before and before_each before_each "setup the test accounts", { given 'a current a/c with $200', { current = new Account(200) This will be done before } and 'a savings a/c with $300', { each scenario savings = new Account(300) } } scenario "A client can transfer money from a current to a savings a/c", { when 'you transfer $50 from the current a/c to the savings a/c', { current.transferTo(savings, 50) } then 'the savings a/c should have $350 and the current a/c $150', { savings.balance.shouldBe 350 } and 'the current a/c should have $150', { current.balance.shouldBe 150 } } scenario "A client is not allowed to transfer a negative amount", { when "you try to transfer a negative amount", { transferNegativeAmount = { current.transferTo(savings, -50) } } then "an IllegalTransferException should be thrown", { ensureThrows(IllegalTransferException.class) { transferNegativeAmount() } } }
  • 27.
    Easyb fixtures Shared behaviour Refactor common code in easyb scenarios shared_behavior "shared behaviors", {   given "a string", {     var = "" Common behavior (‘shared_behavior’)   }   when "the string is hello world", {     var = "hello world"   } } scenario "first scenario", {   it_behaves_as "shared behaviors"     then "the string should start with hello", { Reused here (‘it_behaves_as’)...     var.shouldStartWith "hello"   } } scenario "second scenario", {   it_behaves_as "shared behaviors"     then "the string should end with world", { ...and here     var.shouldEndWith "world"   } }
  • 28.
    Web testing witheasyb Easyb is convenient for web testing BDD/Functional tests Run against a test server, or use Jetty Use your choice of web testing frameworks Selenium JWebUnit ...
  • 29.
    Web testing witheasyb Many options - let’s look at two Selenium Runs in a browser High-level API Runs slower and more work to set up JWebUnit Simulates a browser Runs faster, easy to set up API slightly lower level
  • 30.
    Web testing witheasyb An example - writing functional tests with JWebUnit import net.sourceforge.jwebunit.junit.WebTester before_each "initialize a web test client", { Set up a JWebUnit client given "we have a web test client", { tester = new WebTester() tester.setBaseUrl("http://localhost:8080/tweeter-web") } } scenario "User signup should add a new user", { when "I click on the sign up button on the home page", { tester.beginAt("/home") Click on a link tester.clickLinkWithText("Sign up now!") } and "I enter a new username and password", { tester.setTextField("username", "jane") Enter some values tester.setTextField("password", "tiger") tester.submit() } then "the application should log me on as the new user and show a welcome message", { tester.assertTextPresent("Hi jane!") } Check the results }
  • 31.
    Easyb reports The easybHTML report Test results summary Unimplemented stories Failed stories
  • 32.
    Easyb reports The easybHTML report Test results summary Test failure details Unimplemented stories
  • 33.
    Other Approaches How doeseasyb compare with other tools? Cucumber, RSpec (Ruby) - very similar to easyb FitNesse - wikis and tables Concordion - marked-up HTML
  • 34.
    FitNesse FitNesse - wiki-basedacceptance tests Test data is written at tables on a Wiki Java classes implement the tests behind the scenes
  • 35.
    FitNesse FitNesse - wiki-basedacceptance tests Test data and scenarios as a table Test data Expected results
  • 36.
    FitNesse FitNesse - wiki-basedacceptance tests Testers can write/edit the Wiki pages You can also import to and from Excel
  • 37.
    FitNesse FitNesse - wiki-based acceptance tests public class TransferMoneyBetweenAccounts { Tests are implemented by private BigDecimal savingsBalance; Java classes private BigDecimal currentBalance; private BigDecimal transfer; private BigDecimal finalSavingsBalance; Each column has a private BigDecimal finalCurrentBalance; private boolean exceptionThrown; field in the class public void setSavingsBalance(BigDecimal savingsBalance) {...} public void setCurrentBalance(BigDecimal currentBalance) {...} public void setTransfer(BigDecimal transfer) {...} public BigDecimal finalCurrentBalance() {...} Expected results have public BigDecimal finalSavingsBalance() {...} getters public boolean exceptionThrown() {...} public void execute() { Account currentAccount = new Account(currentBalance); Account savingsAccount = new Account(savingsBalance); exceptionThrown = false; try { currentAccount.transferTo(savingsAccount, transfer); Performing the test finalCurrentBalance = currentAccount.getBalance(); finalSavingsBalance = savingsAccount.getBalance(); } catch (IllegalTransferException e) { exceptionThrown = true; } }
  • 38.
    Commercial options? There arealso some commercial tools out there... GreenPepper Supports tables and BDD-style Nice tool integration (Confluence, Maven,...) Twixt Thoughtworks product, focus on web testing Others?
  • 39.
    Thank You John Ferguson Smart Wakaleo Consulting Ltd. http://www.wakaleo.com Email: john.smart@wakaleo.com Twitter: wakaleo