Bdd for-dso-1227123516572504-8
Upcoming SlideShare
Loading in...5
×

Like this? Share it with your network

Share
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
581
On Slideshare
581
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
20
Comments
0
Likes
0

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Test-Behaviour- } Driven Development Kerry Buckley
  • 2. Clearing up some Misconceptions
  • 3. TDD is not about testing
  • 4. TDD does not mean handing acceptance tests to developers
  • 5. TDD is a design activity
  • 6. Software design isemergent, and happens during development
  • 7. Why TDD?• Makes you think about required behaviour• Reduces speculative code• Provides documentation• Improves quality
  • 8. Evolution
  • 9. Dirty Hacking
  • 10. Automated Testing
  • 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. 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. Test-First Development
  • 14. Test-First Development Write Write tests code Start Failing Done tests
  • 15. Test-DrivenDevelopment
  • 16. Test-Driven DevelopmentClean Failingcode test Refactor All tests pass
  • 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. Bottom-Up
  • 19. Behaviour-Driven Development
  • 20. Behaviour-Driven DevelopmentVerification SpecificationState-based Interaction-basedBottom-up Outside-inTesting tool Design tool Invention Discovery
  • 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. 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. 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. 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. Matchers (HamCrest)assertThat(string, equalTo("foo"));assertThat(array, hasItem("bar"));assertThat(obj, instanceOf(String.class));assertThat(number, greaterThan(42));
  • 26. Outside-In
  • 27. Integration Testing
  • 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. 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. Unit Testing
  • 31. Interaction-Based
  • 32. Mock Objects Mock Mock
  • 33. Classicists v Mockists
  • 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. Boundary Objects
  • 36. Mocking Patterns• Record and playback• Specify expectations before running• Check expectations after running
  • 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. 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. 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. 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. 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. 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. 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. 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. 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. 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