Presentation is loading. Please wait.

Presentation is loading. Please wait.

Test Driven Lasse Koskela Chapter 4: Concepts and Patterns for TDD

Similar presentations


Presentation on theme: "Test Driven Lasse Koskela Chapter 4: Concepts and Patterns for TDD"— Presentation transcript:

1 Test Driven Lasse Koskela Chapter 4: Concepts and Patterns for TDD
Paul Ammann

2 Overview Lots of Stuff in This Chapter
How to Write Tests and Make Them Pass Essential Testing Concepts Closer Look into Test Doubles Guidelines for Testable Designs Unit-Testing Patterns Working With Legacy Code Lots of Stuff in This Chapter 9/20/2018

3 How to Write Tests And Make Them Pass
Test Selection Strategies Details-First vs. Big-Picture Details-First Offers Concrete Progress, but Big-Picture Fleshes Out Overall Design Judgment Call In Any Given Situation Uncertain vs. Familiar Attacking Uncertainty Can Reduce Risk Familiar Code May Have Large Payoff High Value vs. Low Hanging Fruit Usually, High Value is Better Happy Path vs. Error Situations Happy Path First – Mostly for Value Sometimes Error Situations Help Define Remainder as Happy Path Keep Your Options in Mind; Avoid a Rut 9/20/2018

4 How to Write Tests And Make Them Pass(2)
Implementation Strategies Faking It Useful Strategy For Handling Big Steps Incurs Later Obligations To Squeeze Out Fakes Triangulation Strategy For Evolving Towards More General Implementation Use To Drive Out Hard Coded Solutions Obvious Implementation Sometimes The Correct Solution Really Is Simple Try It And See If Tests Fail, Back It Out Goal Is To Get To Green Fast 9/20/2018

5 How to Write Tests And Make Them Pass(3)
Prime Guidelines for Test Driving Do. Not. Skip. Refactoring. The Design Cycle for TDD is Crucial Skipping This Step Leads to Code/Test Bloat Result Is Unmaintainable Software Get To Green Fast Write Code That Passes The Tests First Then Worry About Refactoring Slow Down After a Mistake Mistakes Indicate That Your Reach Exceeds Your Grasp Back Off and Try Smaller Steps The Tests Are The Oracle That Keeps You On Track The First Rule Is The Most Important 9/20/2018

6 Essential Testing Concepts
Fixtures are the Context for Tests Holistic View of State Fixtures Remove Duplication Bloated Tests Are Hard to Read and Hard to Maintain Fixtures Allow For Focused Tests Test Doubles Stand In for Dependencies Example: java.sql.ResultSet Details Depend on Database Used More on Doubles in Later Slides Real-World JUnit Tests Can’t Avoid Some Complexities 9/20/2018

7 Essential Testing Concepts(2)
State and Interaction-Based Testing State-Based Testing Idea Is To Look At Variable State To Verifying Result @Test public void notEmpty() { Collection<String> c = new ArrayList<String>(); assertTrue (c.isEmpty()); c.add(“Bob”); assertFalse(c.isEmpty()); } Testing For Interactions Goal: Did The Expected Methods Calls Happen In The Right Order? Usually Requires Some Sort of Double We lean on interaction-based testing to verify how an object talks to its collaborators; we lean on state-based testing to verify how well the object listens. 9/20/2018

8 Closer Look Into Test Doubles
Replace Object with Double If Real Object is Too Slow It’s Not Available It Depends on Something That’s Not Available Its Too Difficult To Instantiate Or Configure For a Test Examples How to test exceptions, such as “Dead”code? An unplugged network cable? How to interact with something that’s nondeterministic? Doubles Are Key To Unit Testing 9/20/2018

9 Closer Look Into Test Doubles(2)
Example of a Test Double Next Slide Stubs, Fakes, and Mocks Stub: Simplest Possible Implementation Fake: Still Hand Coded, But A Degree More Sophisticated Mock: Usually Generated By Tools Mock Objects in Action Next slide Checking Correct Behavior is Complicated! 9/20/2018

10 Test Double Example: State Testing
9/20/2018

11 Test Double Example: Interaction Testing
9/20/2018

12 Guidelines for Testable Designs
Choose Composition Over Inheritance General Advice For Normal Coding And Testing More Verbose, But Worth It Avoid Static and Singleton These Are Hard To Double Static class names are hardcoded. How to replace at test time? This Can Conflict With Normal Coding Advice Consider Factories! Test Requirements Impact Code! 9/20/2018

13 Dependency Example: Static Method
4.4. Code smell: methods obtaining dependencies through static method calls Dependency Example: Static Method public class OrderProcessor { public void process(Order order) { PricingService service = PricingService.getInstance(); // use the PricingService object for processing the order } 9/20/2018

14 Exploiting a Seam 9/20/2018

15 Injecting Dependencies: Easy Test!
public class OrderProcessorTest { @Test public void testOrderProcessorWithDependencyInjection() throws Exception { OrderProcessor p = new OrderProcessor(); p.setPricingService(new FakePricingService()); ... }} 9/20/2018

16 Unit Testing Patterns Assertion Patterns
Resulting State Assertion Most Common Usage Guard Assertion Test Both Before and After The Action (precondition testing) Delta Assertion Verify Part of the State – Eg, List is One Bigger Than Before Custom Assertion Encodes Complex Verification Rules Interaction Assertion Verification For Interaction Tests Choose and Use Standard Patterns 9/20/2018

17 Example Interaction Assertion
9/20/2018

18 Fowler: Conventional JUnit Example
4.4. Code smell: methods obtaining dependencies through static method calls Fowler: Conventional JUnit Example public class OrderStateTester extends TestCase { private static String TALISKER = "Talisker"; private static String HIGHLAND_PARK = "Highland Park"; private Warehouse warehouse = new WarehouseImpl(); protected void setUp() throws Exception { warehouse.add(TALISKER, 50); warehouse.add(HIGHLAND_PARK, 25); } public void testOrderIsFilledIfEnoughInWarehouse() { Order order = new Order(TALISKER, 50); order.fill(warehouse); assertTrue(order.isFilled()); assertEquals(0, warehouse.getInventory(TALISKER)); public void testOrderDoesNotRemoveIfNotEnough() { Order order = new Order(TALISKER, 51); assertFalse(order.isFilled()); assertEquals(50, warehouse.getInventory(TALISKER)); 9/20/2018

19 4.4. Code smell: methods obtaining dependencies through static method calls
Fowler: jMock Version public class OrderInteractionTester extends MockObjectTestCase { private static String TALISKER = “Talisker”; public void testFillingRemovesInventoryIfInStock() { //setup - data Order order = new Order(TALISKER, 50); Mock warehouseMock = new Mock(Warehouse.class); // constructor //setup - expectations warehouseMock.expects(once()).method("hasInventory") .with(eq(TALISKER),eq(50)) .will(returnValue(true)); warehouseMock.expects(once()).method("remove") .with(eq(TALISKER), eq(50)) .after("hasInventory"); //exercise order.fill((Warehouse) warehouseMock.proxy()); //verify warehouseMock.verify(); assertTrue(order.isFilled()); } public void testFillingDoesNotRemoveIfNotEnoughInStock() { Order order = new Order(TALISKER, 51); Mock warehouse = mock(Warehouse.class); // vs. mock call warehouse.expects(once()).method("hasInventory") .withAnyArguments() .will(returnValue(false)); order.fill((Warehouse) warehouse.proxy()); assertFalse(order.isFilled()); }} 9/20/2018

20 Fowler: EasyMock Example
4.4. Code smell: methods obtaining dependencies through static method calls Fowler: EasyMock Example public class OrderEasyTester extends TestCase { private static String TALISKER = "Talisker"; private MockControl warehouseControl; private Warehouse warehouseMock; public void setUp() { warehouseControl = MockControl.createControl(Warehouse.class); warehouseMock = (Warehouse) warehouseControl.getMock(); } public void testFillingRemovesInventoryIfInStock() { //setup - data Order order = new Order(TALISKER, 50); //setup - expectations warehouseMock.hasInventory(TALISKER, 50); warehouseControl.setReturnValue(true); warehouseMock.remove(TALISKER, 50); warehouseControl.replay(); //exercise order.fill(warehouseMock); //verify warehouseControl.verify(); assertTrue(order.isFilled()); 9/20/2018

21 Fowler/Meszaros “Double” Definitions
A Test Double is anything that stands in for a real object Dummy Used to fill parameter lists Fake Actual working implementations, but take shortcuts Example: In Memory Database Stub Canned answers to calls made during tests, but useless elsewhere Mock Objects preprogrammed with expectations that form a specification of the calls they expect to receive Various Levels of Complexity 9/20/2018

22 Fowler: Stub Example public interface MailService {
4.4. Code smell: methods obtaining dependencies through static method calls Fowler: Stub Example public interface MailService { public void send (Message msg); } public class MailServiceStub implements MailService { private List<Message> messages = new ArrayList<Message>(); public void send (Message msg) { messages.add(msg); public int numberSent() { return messages.size(); } } // Usage class OrderStateTester... public void testOrderSendsMailIfUnfilled() { Order order = new Order(TALISKER, 51); MailServiceStub mailer = new MailServiceStub(); order.setMailer(mailer); order.fill(warehouse); assertEquals(1, mailer.numberSent()); 9/20/2018

23 Fowler: Mock Version class OrderInteractionTester...
4.4. Code smell: methods obtaining dependencies through static method calls Fowler: Mock Version class OrderInteractionTester... public void testOrderSendsMailIfUnfilled() { Order order = new Order(TALISKER, 51); Mock warehouse = mock(Warehouse.class); Mock mailer = mock(MailService.class); order.setMailer((MailService) mailer.proxy()); mailer.expects(once()).method("send"); warehouse.expects(once()).method("hasInventory") .withAnyArguments() .will(returnValue(false)); order.fill((Warehouse) warehouse.proxy()); } 9/20/2018

24 Unit Testing Patterns (2)
Fixture Patterns Parameterized Creation Method Populating Complex Set Of Objects Object Mother Aggregate of Creation Methods Automated TearDown More Important For Integration Testing Than Unit Testing Fixtures Need Attention Too 9/20/2018

25 Unit Testing Patterns (3)
Test Patterns Parameterized Test (see next slide) Self Shunt The Double Is The Test Class Intimate Inner Class Sharing Between Test Class and Test Double Classes Privileged Access Reflection-Based Injection Approaches For Legacy Code (Careful) Extra Constructor Compensates For Classes Not Designed For Testing Tests Need To Accommodate A Variety of Real Code 9/20/2018

26 Parameterized JUnit Example
9/20/2018

27 Working With Legacy Code
Test-Driven Legacy Development Analyzing the Change Change Points and Inflection Points Change Code at Change Points See Effects At Inflection Points Hopefully, The Points Are Close Together… Preparing for the Change Install Tests To Capture Current Behavior of Inflection Point Test-Driving the Change Add Tests To Capture New Behavior, Also At Inflection Point Turning Legacy Code Into TDD Code 9/20/2018


Download ppt "Test Driven Lasse Koskela Chapter 4: Concepts and Patterns for TDD"

Similar presentations


Ads by Google