Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Clean Test Code

1,270 views

Published on

My session "Clean Test Code" given at Agile Testing Days 2014: http://www.agiletestingdays.com/session/clean-test-code/

Published in: Software
  • Be the first to comment

  • Be the first to like this

Clean Test Code

  1. 1. David Völkel, @davidvoelkel Clean Test Code Agile Testing Days 11.11.2014
  2. 2. 2 @davidvoelkel Dev & Consultant Software Craftsman Test-Driven Development Software Design @softwerkskammer
  3. 3. Dirty Test Code technical debt velocity decrease costs latency agile
  4. 4. Clean Tests 4 attributes reliable readable redundancy-free focused Conclusion Q&A
  5. 5. xUnit- Patterns BDD Functional tests setup arrange given Input rows execute act when “Fixture“ verify assert then Output rows [teardown] [annihilate] Test Phases Input Output
  6. 6. Reliable Mind complexity, so avoid •boolean assertions assertTrue(age >= 18); assertThat(age, greaterThan(17))
  7. 7. Reliable Mind complexity, so avoid •boolean assertions •conditionals & complex loops boolean containsName = false; for (String name: names) { if (name.equals("David")) { containsName = true; } } assertTrue(containsName); assertThat(names, hasItem("David"));
  8. 8. Readable Read >> write Executable specifications Living documentation
  9. 9. Abstraction avoid irrelevant details
  10. 10. Test Method Body Gerard Meszaros: „When it is not important for something to be seen in the test method, it is important that it not be seen in the test method! “
  11. 11. “In the order form the user should be able to finish the order process by pressing the cancel button”
  12. 12. @Test public void cancelProcess_inOrderForm() { server.runningProcesses(0); ProcessStatus process = server.startProcess(Process.ORDER); processInstanceId = process.getInstanceId(); server.runningProcesses(1); server.expectUserForm(processInstanceId, ORDER_FORM); Form form = new Form(); form.setOrderDate("01.01.2015"); form.setStandardDelivery(false); String taskId = server.taskIdFor(processInstanceId); controller.submit(form, Mockito.mock(BindingResult.class), null, taskId, null, CANCEL); server.runningProcesses(0); } “In the order form the user should be able to finish the order process by pressing the cancel button”
  13. 13. @Test public void cancelProcess_inOrderForm() { server.runningProcesses(0); ProcessStatus process = server.startProcess(Process.ORDER); processInstanceId = process.getInstanceId(); server.runningProcesses(1); server.expectUserForm(processInstanceId, ORDER_FORM); Form form = new Form(); form.setOrderDate("01.01.2015"); form.setStandardDelivery(false); String taskId = server.taskIdFor(processInstanceId); controller.submit(form, Mockito.mock(BindingResult.class), null, taskId, null, CANCEL); server.runningProcesses(0); } “In the order form the user should be able to finish the order process by pressing the cancel button” „Testscript“ “Incidental Details”
  14. 14. @Test public void cancelProcess_inOrderForm() { server.runningProcesses(0); ProcessStatus process = server.stareProcess(Process.ORDER); processInstanceId = process.getInstanceId(); server.runningProcesses(1); server.expectUserForm(processInstanceId, ORDER_FORM); Form form = new Form(); form.setOrderDate("01.01.2015"); form.setStandardDelivery(false); String taskId = server.taskIdFor(processInstanceId); controller.submit(form, Mockito.mock(BindingResult.class), null, taskId, null, CANCEL); server.runningProcesses(0); } FORM CANCEL Signal-Noise-Ratio? Single Level of Abstraction? “In the order form the user should be able to finish the order process by pressing the cancel button”
  15. 15. @Test public void cancelProcess_inOrderForm() { inForm(ORDER_FORM); submitFormWithButton(CANCEL); noProcessRunning(); } “In the order form the user should be able to finish the order process by pressing the cancel button”
  16. 16. Names
  17. 17. Test class names public class AnOrderProcess { OrderProcess process; @Before public void createOrderProcess() { process = new OrderProcess(); } object under test
  18. 18. public class AnOrderProcess { OrderProcess process; @Before public void createOrderProcess() { process = new OrderProcess(); } @Test public void inOrderForm_cancel() { process.setState(ORDER_FORM); process.submit(CANCEL_BUTTON); assertThat("process canceled", process.isCanceled(), equalTo(true)); } Test method names object under test
  19. 19. public class AnOrderProcess { OrderProcess process; @Before public void createOrderProcess() { process = new OrderProcess(); } @Test public void inOrderForm_cancel() { process.setState(ORDER_FORM); process.submit(CANCEL_BUTTON); assertThat("process canceled", process.isCanceled(), equalTo(true)); } Test method names object under test setup
  20. 20. @Before public void createOrderProcess() { process = new OrderProcess(); } @Test public void inOrderForm_cancel() { process.setState(ORDER_FORM); process.submit(CANCEL_BUTTON); assertThat("process canceled", process.isCanceled(), equalTo(true)); } Test method names setup execute
  21. 21. @Before public void createOrderProcess() { process = new OrderProcess(); } @Test public void inOrderForm_cancel() { process.setState(ORDER_FORM); process.submit(CANCEL_BUTTON); assertThat("process canceled", process.isCanceled(), equalTo(true)); } Test method names setup execute verify
  22. 22. Audience? test maintainer search test failure cause business
  23. 23. Communicate comprehensively OuT + setup + execute + verify Distribute: Class, method name, verify
  24. 24. Redundancy-free
  25. 25. Hierarchical tests public class AnOrderProcess { @Before public void createOrderProcess() { process = new OrderProcess(); } public class InOrderForm { @Before public void inOrderForm() { process.setState(ORDER_FORM); } @Test public void whenCanceled_processIsStopped() { process.submit(CANCEL_BUTTON); assertThat("process stopped", process.isStopped(), equalTo(true)); } @Test public void whenBought_orderIsConfirmed() { process.submit(BUY_NOW_BUTTON); assertThat("state", process.getState(), equalTo(ORDER_CONFIRMED)); } } … extract common setup
  26. 26. OuT Hierarchical tests setup execute verify
  27. 27. Helper methods Object Mother Test Data Builder aCustomer("David"); CustomerTest.aCustomer("David"); CustomerMother.aCustomer("David"); CustomerMother.aCustomer("David", „Völkel"); CustomerMother.aCustomer(null, „Völkel", null, null, null, null, birthday); aCustomer().withLastName("Völkel") .withBirthDay(birthDay) .build(); Common test data
  28. 28. void assertMoneyEquals(Money expected, Money actual) { assertEquals("currency", expected.getCurrency(),actual.getCurrency()); assertEquals("amount", expected.getAmount(), actual.getAmount()); } Matcher<Money> equalTo(Money money) { return allOf( property(money, Money::getCurrency, "currency"), property(money, Money::getAmount, "amount")); } Custom asserts via helper methods Composed Hamcrest Matchers Common verify
  29. 29. "Single Concept per Test" "One Execute per Test" "One Assert per Test" Focused
  30. 30. State vs. testability Focused
  31. 31. „Listen to your tests!“ Hard-to-test Code
  32. 32. Clean Tests 1.reliable 2.readable 3.redundancy-free 4.focussed
  33. 33. Clean Test Code, stay agile!
  34. 34. Resources Books „Clean Code“, Robert C. Martin „xUnit Test Patterns“, Gerard Meszaros „Effective Unittesting“, Lasse Koskela „Growing Object Oriented Software“, Steve Freeman, Nat Pryce „Specification by Example”, Gojko Adzic Videos Episodes 20-22 http://cleancoders.com/, Robert C. Martin
  35. 35. David Völkel codecentric AG Twitter: @davidvoelkel david.voelkel@codecentric.de www.codecentric.de blog.codecentric.de Q&A 35
  36. 36. Creative Commons ShareAlike 4.0 The images used are public domain and can be found on Wikipedia. License 36

×