• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Bdd for-dso-1227123516572504-8
 

Bdd for-dso-1227123516572504-8

on

  • 484 views

 

Statistics

Views

Total Views
484
Views on SlideShare
484
Embed Views
0

Actions

Likes
0
Downloads
19
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 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 = Adder.new 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.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
    • 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, 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
    • 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
    • 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] = 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
    • 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); to.credit(amount); }}class AccountController def transfer from, to, amount from.debit amount to.credit 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 = AccountController.new 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 = 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
    • 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) 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