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

Like this? Share it with your network

Share

Bdd for-dso-1227123516572504-8

on

  • 562 views

 

Statistics

Views

Total Views
562
Views on SlideShare
562
Embed Views
0

Actions

Likes
0
Downloads
20
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Bdd for-dso-1227123516572504-8 Presentation 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