0
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 is
emergent, 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...
Are You Really Testing
     Your Code?
  class Adder
    def add a, b
      a + b
    end
  end

  class AdderTest < Test:...
Test-First Development
Test-First Development

         Write             Write
         tests             code



 Start           Failing      ...
Test-Driven
Development
Test-Driven
        Development
Clean                           Failing
code                             test



    Refac...
State-Based
class DongleTest < Test::Unit::TestCase
  def test_wibble
    # Set up test inputs
    dongle = Dongle.new
   ...
Bottom-Up
Behaviour-Driven
 Development
Behaviour-Driven
      Development
Verification    Specification

State-based    Interaction-based

Bottom-up      Outside-i...
More Descriptive Test
       Names
class AdderTest < Test::Unit::TestCase
  def test_should_add_two_positive_numbers
    a...
RSpec

describe quot;An adderquot; do
  it quot;should add two positive numbersquot; do
    Adder.new.add(2, 2).should == ...
Generated
         Documentation
$ spec -f s adder_spec.rb

An adder
- should add two positive numbers
- should add a posi...
Matchers (RSpec)

@string.should == quot;fooquot;

@array.should_not be_empty

@hash.should have_key(:foo)

@object.should...
Matchers (HamCrest)

assertThat(string, equalTo(quot;fooquot;));

assertThat(array, hasItem(quot;barquot;));

assertThat(o...
Outside-In
Integration Testing
Describing Features

Feature: Transferring money between two accounts

  Scenario: Simple transfer
    Given an account ca...
Describing Features
Given /^an account called '(w*)' containing £(d*)$/ do |name, amount|
  @@accounts ||= {}
  @@accounts...
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 call...
Boundary Objects
Mocking Patterns

• Record and playback
• Specify expectations before running
• Check expectations after running
Mocking Patterns
class AccountController {
  public void transfer(Account from, Account to, int amount) {
    from.debit(a...
EasyMock
public void testTransferShouldDebitSourceAccount() {
  AccountController controller = new AccountController();

 ...
JMock
Mockery context = new Mockery();

public void testTransferShouldDebitSourceAccount() {
  AccountController controlle...
Mockito
public void testTransferShouldDebitSourceAccount() {
  AccountController controller = new AccountController();

  ...
RSpec
describe 'Making a transfer' do
  it 'should debit the source account' do
    controller = AccountController.new

  ...
Not-a-Mock
describe 'Making a transfer' do
  it 'should debit the source account' do
    controller = AccountController.ne...
Other Mock Features
• Stubs (for when you don’t care)
• Mock class/static methods
• Specify return values
• Specify expect...
Good Practices
• Test behaviour, not implementation
• One expectation per test
• Don’t test private methods
• Don’t mock e...
TDD/BDD Summary
• Never write any code without a failing test
• Start from the outside, with acceptance tests
• Drive desi...
Further Reading
Introducing BDD (Dan North)
  http://dannorth.net/introducing-bdd

BDD Introduction
 http://behaviour-driv...
Upcoming SlideShare
Loading in...5
×

TDD, BDD and mocks

11,267

Published on

Published in: Technology, Education
1 Comment
38 Likes
Statistics
Notes
  • Very good slice! cool
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total Views
11,267
On Slideshare
0
From Embeds
0
Number of Embeds
5
Actions
Shares
0
Downloads
404
Comments
1
Likes
38
Embeds 0
No embeds

No notes for slide

Transcript of "TDD, BDD and mocks"

  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 is emergent, 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-Driven Development
  16. 16. Test-Driven Development Clean Failing code test Refactor All tests pass
  17. 17. State-Based class DongleTest < Test::Unit::TestCase def test_wibble # Set up test inputs dongle = Dongle.new dongle.addString(quot;fooquot;) dongle.addRemoteResource(quot;http://foo.com/barquot;) # Exercise functionality under test dongle.wibble! # Verify results are as expected assert_equal(42, dongle.answer) end end
  18. 18. Bottom-Up
  19. 19. Behaviour-Driven Development
  20. 20. Behaviour-Driven Development Verification Specification State-based Interaction-based Bottom-up Outside-in Testing tool Design tool Invention Discovery
  21. 21. More Descriptive Test Names class 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) end end
  22. 22. RSpec describe quot;An adderquot; do it quot;should add two positive numbersquot; do Adder.new.add(2, 2).should == 4 end it quot;should add a positive and a negative numberquot; do Adder.new.add(4, -2).should == 2 end end
  23. 23. Generated Documentation $ spec -f s adder_spec.rb An adder - should add two positive numbers - should add a positive and a negative number Finished in 0.005493 seconds 2 examples, 0 failures
  24. 24. Matchers (RSpec) @string.should == quot;fooquot; @array.should_not be_empty @hash.should have_key(:foo) @object.should be_an_instance_of String lambda { @stack.pop }.should raise_error(StackUnderflowError)
  25. 25. Matchers (HamCrest) assertThat(string, equalTo(quot;fooquot;)); assertThat(array, hasItem(quot;barquot;)); assertThat(obj, instanceOf(String.class)); assertThat(number, greaterThan(42));
  26. 26. Outside-In
  27. 27. Integration Testing
  28. 28. Describing Features Feature: 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 Features Given /^an account called '(w*)' containing £(d*)$/ do |name, amount| @@accounts ||= {} @@accounts[name] = Account.new(amount.to_i) end When /^I transfer £(d*) from (w*) to (w*)$/ do |amount, from, to| AccountController.new.transfer @@accounts[from], @@accounts[to], amount.to_i end Then /^the '(w*)' account should contain £(d*)$/ do |name, amount| @@accounts[name].balance.should == amount.to_i end
  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 Patterns class 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 end end
  38. 38. EasyMock public 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. JMock Mockery 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. Mockito public 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. RSpec describe '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 end end
  42. 42. Not-a-Mock describe '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) end end
  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 Reading Introducing BDD (Dan North) http://dannorth.net/introducing-bdd BDD Introduction http://behaviour-driven.org/Introduction Mock Roles, Not Objects (Freeman, Mackinnon, Pryce, Walnes) http://www.jmock.org/oopsla2004.pdf BDD in Ruby (Dave Astels) http://blog.daveastels.com/files/BDD_Intro.pdf Test 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.

×