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

Bdd for-dso-1227123516572504-8






Total Views
Views on SlideShare
Embed Views



0 Embeds 0

No embeds



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.

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

Bdd for-dso-1227123516572504-8 Bdd for-dso-1227123516572504-8 Presentation Transcript

  • 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 adder = assert_equal 4, adder.add(2, 2) assert_equal 2, adder.add(4, -2) end end
  • 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
  • Test-First Development
  • Test-First Development Write Write tests code Start Failing Done tests
  • Test-DrivenDevelopment
  • Test-Driven DevelopmentClean Failingcode test Refactor All tests pass
  • State-Basedclass DongleTest < Test::Unit::TestCase def test_wibble # Set up test inputs dongle = dongle.addString("foo") dongle.addRemoteResource("") # Exercise functionality under test dongle.wibble! # Verify results are as expected assert_equal(42, dongle.answer) endend
  • Bottom-Up
  • Behaviour-Driven Development
  • Behaviour-Driven DevelopmentVerification SpecificationState-based Interaction-basedBottom-up Outside-inTesting tool Design tool Invention Discovery
  • More Descriptive Test Namesclass AdderTest < Test::Unit::TestCase def test_should_add_two_positive_numbers assert_equal 4,, 2) end def test_should_add_a_positive_and_a_negative_number assert_equal 2,, -2) endend
  • RSpecdescribe "An adder" do it "should add two positive numbers" do, 2).should == 4 end it "should add a positive and a negative number" do, -2).should == 2 endend
  • 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
  • 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)
  • Matchers (HamCrest)assertThat(string, equalTo("foo"));assertThat(array, hasItem("bar"));assertThat(obj, instanceOf(String.class));assertThat(number, greaterThan(42));
  • Outside-In
  • Integration Testing
  • 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
  • Describing FeaturesGiven /^an account called (w*) containing £(d*)$/ do |name, amount| @@accounts ||= {} @@accounts[name] = /^I transfer £(d*) from (w*) to (w*)$/ do |amount, from, to| @@accounts[from], @@accounts[to], amount.to_iendThen /^the (w*) account should contain £(d*)$/ do |name, amount| @@accounts[name].balance.should == amount.to_iend
  • 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 are made• Not stubs!• For your code only!
  • 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(amount);; }}class AccountController def transfer from, to, amount from.debit amount amount endend
  • 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);}
  • 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();}
  • 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);}
  • RSpecdescribe Making a transfer do it should debit the source account do controller = from = stub_everything from to = stub_everything to from.should_receive(:debit).with 42 controller.transfer from, to, 42 endend
  • Not-a-Mockdescribe Making a transfer do it should debit the source account do controller = from = to = from.stub_method :debit => nil to.stub_method :credit => nil controller.transfer from, to, 42 from.should_have_received(:debit).with(42) endend
  • 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
  • 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!
  • 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!
  • Further ReadingIntroducing BDD (Dan North) Introduction Roles, Not Objects(Freeman, Mackinnon, Pryce, Walnes) in Ruby (Dave Astels) all the F***in Time (Brian Liles, video)