Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Acceptance Test Driven Development

2,108 views

Published on

Published in: Technology, Economy & Finance
  • Be the first to comment

Acceptance Test Driven Development

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

×