Test-Behaviour-   } Driven Development              Kerry Buckley
Clearing up some Misconceptions
TDD is not about    testing
TDD does not mean handing acceptance tests to developers
TDD is a design activity
Software design isemergent, and happens during development
Why TDD?• Makes you think about required behaviour• Reduces speculative code• Provides documentation• Improves quality
Evolution
Dirty Hacking
Automated Testing
Automated Testing class Adder   def add a, b     a + b   end end class AdderTest < Test::Unit::TestCase   def test_add    ...
Are You Really Testing     Your Code?  class Adder    def add a, b      a + b    end  end  class AdderTest < Test::Unit::T...
Test-First Development
Test-First Development         Write             Write         tests             code Start           Failing           Do...
Test-DrivenDevelopment
Test-Driven        DevelopmentClean                           Failingcode                             test    Refactor    ...
State-Basedclass DongleTest < Test::Unit::TestCase  def test_wibble    # Set up test inputs    dongle = Dongle.new    dong...
Bottom-Up
Behaviour-Driven Development
Behaviour-Driven      DevelopmentVerification    SpecificationState-based    Interaction-basedBottom-up      Outside-inTesti...
More Descriptive Test       Namesclass AdderTest < Test::Unit::TestCase  def test_should_add_two_positive_numbers    asser...
RSpecdescribe "An adder" do  it "should add two positive numbers" do    Adder.new.add(2, 2).should == 4  end  it "should a...
Generated         Documentation$ spec -f s adder_spec.rbAn adder- should add two positive numbers- should add a positive a...
Matchers (RSpec)@string.should == "foo"@array.should_not be_empty@hash.should have_key(:foo)@object.should be_an_instance_...
Matchers (HamCrest)assertThat(string, equalTo("foo"));assertThat(array, hasItem("bar"));assertThat(obj, instanceOf(String....
Outside-In
Integration Testing
Describing FeaturesFeature: Transferring money between two accounts  Scenario: Simple transfer    Given an account called ...
Describing FeaturesGiven /^an account called (w*) containing £(d*)$/ do |name, amount|  @@accounts ||= {}  @@accounts[name...
Unit Testing
Interaction-Based
Mock Objects Mock   Mock
Classicists v Mockists
Mock Objects• Stand-ins for collaborating objects• Mock the interface, not a specific object• Verify that expected calls ar...
Boundary Objects
Mocking Patterns• Record and playback• Specify expectations before running• Check expectations after running
Mocking Patternsclass AccountController {  public void transfer(Account from, Account to, int amount) {    from.debit(amou...
EasyMockpublic void testTransferShouldDebitSourceAccount() {  AccountController controller = new AccountController();    A...
JMockMockery context = new Mockery();public void testTransferShouldDebitSourceAccount() {  AccountController controller = ...
Mockitopublic void testTransferShouldDebitSourceAccount() {  AccountController controller = new AccountController();    Ac...
RSpecdescribe Making a transfer do  it should debit the source account do    controller = AccountController.new   from = s...
Not-a-Mockdescribe Making a transfer do  it should debit the source account do    controller = AccountController.new    fr...
Other Mock Features• Stubs (for when you don’t care)• Mock class/static methods• Specify return values• Specify expected n...
Good Practices• Test behaviour, not implementation• One expectation per test• Don’t test private methods• Don’t mock every...
TDD/BDD Summary• Never write any code without a failing test• Start from the outside, with acceptance tests• Drive design ...
Further ReadingIntroducing BDD (Dan North)  http://dannorth.net/introducing-bddBDD Introduction http://behaviour-driven.or...
Upcoming SlideShare
Loading in...5
×

Bdd for-dso-1227123516572504-8

415

Published on

0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
415
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
23
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Bdd for-dso-1227123516572504-8

  1. 1. Test-Behaviour- } Driven Development Kerry Buckley
  2. 2. Clearing up some Misconceptions
  3. 3. TDD is not about testing
  4. 4. TDD does not mean handing acceptance tests to developers
  5. 5. TDD is a design activity
  6. 6. Software design isemergent, and happens during development
  7. 7. Why TDD?• Makes you think about required behaviour• Reduces speculative code• Provides documentation• Improves quality
  8. 8. Evolution
  9. 9. Dirty Hacking
  10. 10. Automated Testing
  11. 11. Automated Testing class Adder def add a, b a + b end end class AdderTest < Test::Unit::TestCase def test_add adder = Adder.new assert_equal 4, adder.add(2, 2) assert_equal 2, adder.add(4, -2) end end
  12. 12. Are You Really Testing Your Code? class Adder def add a, b a + b end end class AdderTest < Test::Unit::TestCase def test_add assert_equal 4, 2 + 2 end end
  13. 13. Test-First Development
  14. 14. Test-First Development Write Write tests code Start Failing Done tests
  15. 15. Test-DrivenDevelopment
  16. 16. Test-Driven DevelopmentClean Failingcode test Refactor All tests pass
  17. 17. State-Basedclass DongleTest < Test::Unit::TestCase def test_wibble # Set up test inputs dongle = Dongle.new dongle.addString("foo") dongle.addRemoteResource("http://foo.com/bar") # Exercise functionality under test dongle.wibble! # Verify results are as expected assert_equal(42, dongle.answer) endend
  18. 18. Bottom-Up
  19. 19. Behaviour-Driven Development
  20. 20. Behaviour-Driven DevelopmentVerification SpecificationState-based Interaction-basedBottom-up Outside-inTesting tool Design tool Invention Discovery
  21. 21. More Descriptive Test Namesclass AdderTest < Test::Unit::TestCase def test_should_add_two_positive_numbers assert_equal 4, Adder.new.add(2, 2) end def test_should_add_a_positive_and_a_negative_number assert_equal 2, Adder.new.add(4, -2) endend
  22. 22. RSpecdescribe "An adder" do it "should add two positive numbers" do Adder.new.add(2, 2).should == 4 end it "should add a positive and a negative number" do Adder.new.add(4, -2).should == 2 endend
  23. 23. Generated Documentation$ spec -f s adder_spec.rbAn adder- should add two positive numbers- should add a positive and a negative numberFinished in 0.005493 seconds2 examples, 0 failures
  24. 24. Matchers (RSpec)@string.should == "foo"@array.should_not be_empty@hash.should have_key(:foo)@object.should be_an_instance_of Stringlambda { @stack.pop }.should raise_error(StackUnderflowError)
  25. 25. Matchers (HamCrest)assertThat(string, equalTo("foo"));assertThat(array, hasItem("bar"));assertThat(obj, instanceOf(String.class));assertThat(number, greaterThan(42));
  26. 26. Outside-In
  27. 27. Integration Testing
  28. 28. Describing FeaturesFeature: Transferring money between two accounts Scenario: Simple transfer Given an account called source containing £100 And an account called destination containing £50 When I transfer £20 from source to destination Then the source account should contain £80 And the destination account should contain £70
  29. 29. Describing FeaturesGiven /^an account called (w*) containing £(d*)$/ do |name, amount| @@accounts ||= {} @@accounts[name] = Account.new(amount.to_i)endWhen /^I transfer £(d*) from (w*) to (w*)$/ do |amount, from, to| AccountController.new.transfer @@accounts[from], @@accounts[to], amount.to_iendThen /^the (w*) account should contain £(d*)$/ do |name, amount| @@accounts[name].balance.should == amount.to_iend
  30. 30. Unit Testing
  31. 31. Interaction-Based
  32. 32. Mock Objects Mock Mock
  33. 33. Classicists v Mockists
  34. 34. Mock Objects• Stand-ins for collaborating objects• Mock the interface, not a specific object• Verify that expected calls are made• Not stubs!• For your code only!
  35. 35. Boundary Objects
  36. 36. Mocking Patterns• Record and playback• Specify expectations before running• Check expectations after running
  37. 37. Mocking Patternsclass AccountController { public void transfer(Account from, Account to, int amount) { from.debit(amount); to.credit(amount); }}class AccountController def transfer from, to, amount from.debit amount to.credit amount endend
  38. 38. EasyMockpublic void testTransferShouldDebitSourceAccount() { AccountController controller = new AccountController(); Account from = createMock(Account.class); Account to = createNiceMock(Account.class); from.debit(42); replay(from); replay(to); controller.transfer(from, to, 42); verify(from);}
  39. 39. JMockMockery context = new Mockery();public void testTransferShouldDebitSourceAccount() { AccountController controller = new AccountController(); Account from = context.mock(Account.class); Account to = context.mock(Account.class); context.checking(new Expectations() {{ oneOf(from).debit(42); }}); controller.transfer(from, to, 42); context.assertIsSatisfied();}
  40. 40. Mockitopublic void testTransferShouldDebitSourceAccount() { AccountController controller = new AccountController(); Account from = mock(Account.class); Account to = mock(Account.class); controller.transfer(from, to, 42); verify(from).debit(42);}
  41. 41. RSpecdescribe Making a transfer do it should debit the source account do controller = AccountController.new from = stub_everything from to = stub_everything to from.should_receive(:debit).with 42 controller.transfer from, to, 42 endend
  42. 42. Not-a-Mockdescribe Making a transfer do it should debit the source account do controller = AccountController.new from = Account.new to = Account.new from.stub_method :debit => nil to.stub_method :credit => nil controller.transfer from, to, 42 from.should_have_received(:debit).with(42) endend
  43. 43. Other Mock Features• Stubs (for when you don’t care)• Mock class/static methods• Specify return values• Specify expected number of calls• Specify method ordering• Raise exceptions on method calls
  44. 44. Good Practices• Test behaviour, not implementation• One expectation per test• Don’t test private methods• Don’t mock everything• Stub queries; mock actions• Tell, don’t ask• Listen to test smells!
  45. 45. TDD/BDD Summary• Never write any code without a failing test• Start from the outside, with acceptance tests• Drive design inwards using mock objects• Tests should be descriptive specifications• Red – Green – Refactor• YAGNI• TATFT!
  46. 46. Further ReadingIntroducing BDD (Dan North) http://dannorth.net/introducing-bddBDD Introduction http://behaviour-driven.org/IntroductionMock Roles, Not Objects(Freeman, Mackinnon, Pryce, Walnes) http://www.jmock.org/oopsla2004.pdfBDD in Ruby (Dave Astels) http://blog.daveastels.com/files/BDD_Intro.pdfTest all the F***in Time (Brian Liles, video) http://www.icanhaz.com/tatft
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×