Acceptance Test Driven Development

2,001 views
1,909 views

Published on

Published in: Technology, Economy & Finance
0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,001
On SlideShare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
0
Comments
0
Likes
4
Embeds 0
No embeds

No notes for slide

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

×