Bdd for-dso-1227123516572504-8
-
Upload
frederic-delorme -
Category
Documents
-
view
387 -
download
0
Transcript of Bdd for-dso-1227123516572504-8
![Page 1: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/1.jpg)
Test-Behaviour-
Kerry Buckley
Driven Development}
![Page 2: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/2.jpg)
Clearing up some Misconceptions
![Page 3: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/3.jpg)
TDD is not about testing
![Page 4: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/4.jpg)
TDD does not mean handing acceptance tests to developers
![Page 5: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/5.jpg)
TDD is a design activity
![Page 6: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/6.jpg)
Software design is emergent, and happens
during development
![Page 7: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/7.jpg)
Why TDD?
• Makes you think about required behaviour
• Reduces speculative code
• Provides documentation
• Improves quality
![Page 8: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/8.jpg)
Evolution
![Page 9: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/9.jpg)
Dirty Hacking
![Page 10: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/10.jpg)
Automated Testing
![Page 11: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/11.jpg)
Automated Testingclass Adder def add a, b a + b endend
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) endend
![Page 12: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/12.jpg)
Are You Really Testing Your Code?
class Adder def add a, b a + b endend
class AdderTest < Test::Unit::TestCase def test_add assert_equal 4, 2 + 2 endend
![Page 13: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/13.jpg)
Test-First Development
![Page 14: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/14.jpg)
Test-First Development
Failingtests
Start Done
Writecode
Writetests
![Page 15: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/15.jpg)
Test-Driven Development
![Page 16: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/16.jpg)
Test-Driven Development
Failingtest
Cleancode
All tests pass
Refactor
![Page 17: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/17.jpg)
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
![Page 18: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/18.jpg)
Bottom-Up
![Page 19: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/19.jpg)
Behaviour-Driven Development
![Page 20: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/20.jpg)
Behaviour-Driven Development
Verification Specification
State-based Interaction-based
Bottom-up Outside-in
Testing tool Design tool
Invention Discovery
![Page 21: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/21.jpg)
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) endend
![Page 22: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/22.jpg)
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 endend
![Page 23: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/23.jpg)
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
![Page 24: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/24.jpg)
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)
![Page 25: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/25.jpg)
Matchers (HamCrest)
assertThat(string, equalTo("foo"));
assertThat(array, hasItem("bar"));
assertThat(obj, instanceOf(String.class));
assertThat(number, greaterThan(42));
![Page 26: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/26.jpg)
Outside-In
![Page 27: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/27.jpg)
Integration Testing
![Page 28: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/28.jpg)
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
![Page 29: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/29.jpg)
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_iend
Then /^the '(\w*)' account should contain £(\d*)$/ do |name, amount| @@accounts[name].balance.should == amount.to_iend
![Page 30: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/30.jpg)
Unit Testing
![Page 31: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/31.jpg)
Interaction-Based
![Page 32: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/32.jpg)
Mock Objects
Mock Mock
![Page 33: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/33.jpg)
Classicists v Mockists
![Page 34: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/34.jpg)
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!
![Page 35: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/35.jpg)
Boundary Objects
![Page 36: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/36.jpg)
Mocking Patterns
• Record and playback
• Specify expectations before running
• Check expectations after running
![Page 37: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/37.jpg)
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
![Page 38: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/38.jpg)
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);}
![Page 39: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/39.jpg)
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();}
![Page 40: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/40.jpg)
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);}
![Page 41: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/41.jpg)
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 endend
![Page 42: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/42.jpg)
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
![Page 43: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/43.jpg)
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
![Page 44: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/44.jpg)
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!
![Page 45: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/45.jpg)
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!
![Page 46: Bdd for-dso-1227123516572504-8](https://reader033.fdocuments.in/reader033/viewer/2022052822/554f6520b4c905c8088b4ce3/html5/thumbnails/46.jpg)
Further ReadingIntroducing BDD (Dan North)
http://dannorth.net/introducing-bdd
BDD Introductionhttp://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