Skip to content

Latest commit

 

History

History
73 lines (64 loc) · 4.45 KB

test-doubles.md

File metadata and controls

73 lines (64 loc) · 4.45 KB

Table of contents

Finding the code

Lab Exercise 1

  • Your task is to test the DeliveryController.UpdateDelivery method
  • If you create the simplest test you possibly can, the test won't run
    • You get an error: "Failure sending mail."
    • There is a C# example of such a test here
  • There are two collaborators - EmailGateway and MapService.
    • Should you replace both with test doubles?
    • What kind of test doubles?
  • The first test - Test_UpdateDelivery_UpdatesDelivery_ToArrived - can be made to work if you inject email gateway
    • There is a C# demo of this here
      • In here, both email gateway and map service are injected
      • But they are not stubbed, so you still get an error when you run the test
    • By switching to a stub of email gateway, you can make the first test pass:
      • In call to constructor, replace new EmailGateway() with stubGateway
      • Alt + Enter => Create local variable
      • Add = new StubEmailGateway();
      • Alt + Enter => create new type
      • Remove body of unimplemented method in new class
      • Run test again - will pass
    • You don't need a stub of map service to make this test pass
      • The question is, when might you need a test double for map service?

Lab Exercise 2

  • Your task is still to test the DeliveryController.UpdateDelivery method
  • Code from the coding demo can be seen here
  • You have two choices:
    1. Continue where you left off
    2. ...or Use the C# test-start branch and... a. Get the test to pass by creating and passing a stub email gateway b. Decide when a map service double might be needed

C# demo notes

  • This code creates a test double for map service as well as email gateway
    • It actually creates many different types of test double for different jobs in different types of test
  • Examples
    • DUMMY: dummyMapService in Test_UpdateDelivery_SetsOnTimeToFalse_IfDeliveryAfterTenMins
    • STUB: stubMapService (returns data from CalculateEta for the email gateway)
    • MOCK: mockEmailGateway (also a spy)
    • SELF SHUNT (also mock/spy): the test class implements IMapService
    • SPY: (not exactly shown) If you used a mocking framework, it would probably have spies available - but the self shunt code also acts as a spy
    • FAKE: (not shown) If your email service wrote email content out to a log file
  • How to do self shunt using IDE tools:
    • Replace new MockEmailGateway() with this in Test_UpdateDelivery_UpdatesDelivery_ToArrived
    • Let the automated tools guide you through the rest
  • The terminology doesn't matter as much as the ideas
  • Stubs and Fakes are simpler than Mocks and Spies - the latter will fail the test if they are not called correctly.
  • You don’t need to replace a value object with a test double.
    • For instance, the DeliveryController constructor takes a deliverySchedule param
      • This is a list of deliveries which are composed of raw types such as string, float etc
      • so here you just pass in raw data constructed for the purpose of the test - not same thing as test double
  • You might not even need to replace a more complex collaborator with a double.
  • Usually only need a stub if the real collaborator is slow, unreliable or otherwise difficult to use in a unit test.
  • Only need a mock if you need to check the collaborator received correct calls or data.
  • There are two main schools of TDD
    • this advice is from the ‘classic’ or ‘Chicago’ school.
    • Other TDD practitioners may prefer to use doubles for all collaborators even if they are not slow or unreliable
      • to isolate the unit under test.