SlideShare una empresa de Scribd logo
1 de 46
Descargar para leer sin conexión
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_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-Driven
Development
Test-Driven
        Development
Clean                           Failing
code                             test



    Refactor



               All tests pass
State-Based
class 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)
  end
end
Bottom-Up
Behaviour-Driven
 Development
Behaviour-Driven
      Development
Verification    Specification

State-based    Interaction-based

Bottom-up      Outside-in

Testing tool   Design tool

  Invention    Discovery
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
RSpec

describe "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
  end
end
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
Matchers (RSpec)

@string.should == "foo"

@array.should_not be_empty

@hash.should have_key(:foo)

@object.should be_an_instance_of String

lambda { @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 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
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
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 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
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);
}
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();
}
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);
}
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
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
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 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

Más contenido relacionado

La actualidad más candente

TDD CrashCourse Part3: TDD Techniques
TDD CrashCourse Part3: TDD TechniquesTDD CrashCourse Part3: TDD Techniques
TDD CrashCourse Part3: TDD TechniquesDavid Rodenas
 
Introduction to TDD (Test Driven development) - Ahmed Shreef
Introduction to TDD (Test Driven development) - Ahmed ShreefIntroduction to TDD (Test Driven development) - Ahmed Shreef
Introduction to TDD (Test Driven development) - Ahmed ShreefAhmed Shreef
 
TDD (Test Driven Design)
TDD (Test Driven Design)TDD (Test Driven Design)
TDD (Test Driven Design)nedirtv
 
Android Test Driven Development
Android Test Driven DevelopmentAndroid Test Driven Development
Android Test Driven DevelopmentArif Huda
 
Unit testing legacy code
Unit testing legacy codeUnit testing legacy code
Unit testing legacy codeLars Thorup
 
Test driven development
Test driven developmentTest driven development
Test driven developmentJohn Walsh
 
TDD - Test Driven Development
TDD - Test Driven DevelopmentTDD - Test Driven Development
TDD - Test Driven DevelopmentTung Nguyen Thanh
 
Pitfalls Of Tdd Adoption by Bartosz Bankowski
Pitfalls Of Tdd Adoption by Bartosz BankowskiPitfalls Of Tdd Adoption by Bartosz Bankowski
Pitfalls Of Tdd Adoption by Bartosz BankowskiAgileee
 
Test-Driven Development (TDD)
Test-Driven Development (TDD)Test-Driven Development (TDD)
Test-Driven Development (TDD)Brian Rasmussen
 
TDD Flow: The Mantra in Action
TDD Flow: The Mantra in ActionTDD Flow: The Mantra in Action
TDD Flow: The Mantra in ActionDionatan default
 
Software Testing
Software TestingSoftware Testing
Software TestingAdroitLogic
 
An Introduction to Test Driven Development
An Introduction to Test Driven Development An Introduction to Test Driven Development
An Introduction to Test Driven Development CodeOps Technologies LLP
 
Front end unit testing using jasmine
Front end unit testing using jasmineFront end unit testing using jasmine
Front end unit testing using jasmineGil Fink
 
Quick Tour to Front-End Unit Testing Using Jasmine
Quick Tour to Front-End Unit Testing Using JasmineQuick Tour to Front-End Unit Testing Using Jasmine
Quick Tour to Front-End Unit Testing Using JasmineGil Fink
 
Test-Driven Development
Test-Driven DevelopmentTest-Driven Development
Test-Driven DevelopmentJohn Blum
 
iOS Unit Testing
iOS Unit TestingiOS Unit Testing
iOS Unit Testingsgleadow
 

La actualidad más candente (20)

TDD CrashCourse Part3: TDD Techniques
TDD CrashCourse Part3: TDD TechniquesTDD CrashCourse Part3: TDD Techniques
TDD CrashCourse Part3: TDD Techniques
 
Introduction to TDD (Test Driven development) - Ahmed Shreef
Introduction to TDD (Test Driven development) - Ahmed ShreefIntroduction to TDD (Test Driven development) - Ahmed Shreef
Introduction to TDD (Test Driven development) - Ahmed Shreef
 
TDD and BDD and ATDD
TDD and BDD and ATDDTDD and BDD and ATDD
TDD and BDD and ATDD
 
PHPUnit - Unit testing
PHPUnit - Unit testingPHPUnit - Unit testing
PHPUnit - Unit testing
 
Test Driven Development
Test Driven DevelopmentTest Driven Development
Test Driven Development
 
TDD (Test Driven Design)
TDD (Test Driven Design)TDD (Test Driven Design)
TDD (Test Driven Design)
 
Android Test Driven Development
Android Test Driven DevelopmentAndroid Test Driven Development
Android Test Driven Development
 
Unit testing legacy code
Unit testing legacy codeUnit testing legacy code
Unit testing legacy code
 
Test driven development
Test driven developmentTest driven development
Test driven development
 
TDD - Test Driven Development
TDD - Test Driven DevelopmentTDD - Test Driven Development
TDD - Test Driven Development
 
Pitfalls Of Tdd Adoption by Bartosz Bankowski
Pitfalls Of Tdd Adoption by Bartosz BankowskiPitfalls Of Tdd Adoption by Bartosz Bankowski
Pitfalls Of Tdd Adoption by Bartosz Bankowski
 
Test-Driven Development (TDD)
Test-Driven Development (TDD)Test-Driven Development (TDD)
Test-Driven Development (TDD)
 
TDD Flow: The Mantra in Action
TDD Flow: The Mantra in ActionTDD Flow: The Mantra in Action
TDD Flow: The Mantra in Action
 
Software Testing
Software TestingSoftware Testing
Software Testing
 
An Introduction to Test Driven Development
An Introduction to Test Driven Development An Introduction to Test Driven Development
An Introduction to Test Driven Development
 
Front end unit testing using jasmine
Front end unit testing using jasmineFront end unit testing using jasmine
Front end unit testing using jasmine
 
Quick Tour to Front-End Unit Testing Using Jasmine
Quick Tour to Front-End Unit Testing Using JasmineQuick Tour to Front-End Unit Testing Using Jasmine
Quick Tour to Front-End Unit Testing Using Jasmine
 
Tdd and-bdd
Tdd and-bddTdd and-bdd
Tdd and-bdd
 
Test-Driven Development
Test-Driven DevelopmentTest-Driven Development
Test-Driven Development
 
iOS Unit Testing
iOS Unit TestingiOS Unit Testing
iOS Unit Testing
 

Similar a Clearing up some Misconceptions about TDD

Tdd for BT E2E test community
Tdd for BT E2E test communityTdd for BT E2E test community
Tdd for BT E2E test communityKerry Buckley
 
Behaviour-Driven Development
Behaviour-Driven DevelopmentBehaviour-Driven Development
Behaviour-Driven DevelopmentKerry Buckley
 
Unit test candidate solutions
Unit test candidate solutionsUnit test candidate solutions
Unit test candidate solutionsbenewu
 
Acceptance Testing With Selenium
Acceptance Testing With SeleniumAcceptance Testing With Selenium
Acceptance Testing With Seleniumelliando dias
 
Test Driven Development
Test Driven DevelopmentTest Driven Development
Test Driven DevelopmentSheeju Alex
 
Leveling Up With Unit Testing - php[tek] 2023
Leveling Up With Unit Testing - php[tek] 2023Leveling Up With Unit Testing - php[tek] 2023
Leveling Up With Unit Testing - php[tek] 2023Mark Niebergall
 
Workshop quality assurance for php projects - phpdublin
Workshop quality assurance for php projects - phpdublinWorkshop quality assurance for php projects - phpdublin
Workshop quality assurance for php projects - phpdublinMichelangelo van Dam
 
How To Test Everything
How To Test EverythingHow To Test Everything
How To Test Everythingnoelrap
 
關於測試,我說的其實是......
關於測試,我說的其實是......關於測試,我說的其實是......
關於測試,我說的其實是......hugo lu
 
Very basic functional design patterns
Very basic functional design patternsVery basic functional design patterns
Very basic functional design patternsTomasz Kowal
 
Developer Joy - How great teams get s%*t done
Developer Joy - How great teams get s%*t doneDeveloper Joy - How great teams get s%*t done
Developer Joy - How great teams get s%*t doneSven Peters
 
Unit Testing - The Whys, Whens and Hows
Unit Testing - The Whys, Whens and HowsUnit Testing - The Whys, Whens and Hows
Unit Testing - The Whys, Whens and Howsatesgoral
 
MT_01_unittest_python.pdf
MT_01_unittest_python.pdfMT_01_unittest_python.pdf
MT_01_unittest_python.pdfHans Jones
 

Similar a Clearing up some Misconceptions about TDD (20)

TDD
TDDTDD
TDD
 
Tdd for BT E2E test community
Tdd for BT E2E test communityTdd for BT E2E test community
Tdd for BT E2E test community
 
Behaviour-Driven Development
Behaviour-Driven DevelopmentBehaviour-Driven Development
Behaviour-Driven Development
 
Testing
TestingTesting
Testing
 
Unit test candidate solutions
Unit test candidate solutionsUnit test candidate solutions
Unit test candidate solutions
 
Test driven development
Test driven developmentTest driven development
Test driven development
 
Acceptance Testing With Selenium
Acceptance Testing With SeleniumAcceptance Testing With Selenium
Acceptance Testing With Selenium
 
Mspec talk
Mspec talkMspec talk
Mspec talk
 
Test Driven Development
Test Driven DevelopmentTest Driven Development
Test Driven Development
 
Leveling Up With Unit Testing - php[tek] 2023
Leveling Up With Unit Testing - php[tek] 2023Leveling Up With Unit Testing - php[tek] 2023
Leveling Up With Unit Testing - php[tek] 2023
 
Workshop quality assurance for php projects - phpdublin
Workshop quality assurance for php projects - phpdublinWorkshop quality assurance for php projects - phpdublin
Workshop quality assurance for php projects - phpdublin
 
Bdd spex
Bdd spexBdd spex
Bdd spex
 
How To Test Everything
How To Test EverythingHow To Test Everything
How To Test Everything
 
關於測試,我說的其實是......
關於測試,我說的其實是......關於測試,我說的其實是......
關於測試,我說的其實是......
 
Rspec
RspecRspec
Rspec
 
Very basic functional design patterns
Very basic functional design patternsVery basic functional design patterns
Very basic functional design patterns
 
Design for Testability
Design for TestabilityDesign for Testability
Design for Testability
 
Developer Joy - How great teams get s%*t done
Developer Joy - How great teams get s%*t doneDeveloper Joy - How great teams get s%*t done
Developer Joy - How great teams get s%*t done
 
Unit Testing - The Whys, Whens and Hows
Unit Testing - The Whys, Whens and HowsUnit Testing - The Whys, Whens and Hows
Unit Testing - The Whys, Whens and Hows
 
MT_01_unittest_python.pdf
MT_01_unittest_python.pdfMT_01_unittest_python.pdf
MT_01_unittest_python.pdf
 

Clearing up some Misconceptions about TDD

  • 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 is emergent, and happens during development
  • 7. Why TDD? • Makes you think about required behaviour • Reduces speculative code • Provides documentation • Improves quality
  • 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
  • 14. Test-First Development Write Write tests code Start Failing Done tests
  • 16. Test-Driven Development Clean Failing code test Refactor All tests pass
  • 17. State-Based class 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) end end
  • 20. Behaviour-Driven Development Verification Specification State-based Interaction-based Bottom-up Outside-in Testing tool Design tool Invention Discovery
  • 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. RSpec describe "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 end end
  • 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. Matchers (RSpec) @string.should == "foo" @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. Matchers (HamCrest) assertThat(string, equalTo("foo")); assertThat(array, hasItem("bar")); assertThat(obj, instanceOf(String.class)); assertThat(number, greaterThan(42));
  • 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. 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
  • 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!
  • 36. Mocking Patterns • Record and playback • Specify expectations before running • Check expectations after running
  • 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. 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. 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. 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. 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. 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. 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 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