Unit Testing, TDD and the Walking Skeleton


Published on

Slides from my DDD Scotland 2011 session.

Published in: Technology, Education
No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide
  • “ Run quickly” not covered specifically in this deck. Avoiding dependency on external systems will generally permit tests to run fast. Some computationally intensive tests may be slow – consider moving these out of unit test suite. Becomes a serious issue when practicing TDD
  • Unit Testing, TDD and the Walking Skeleton

    1. 1. Unit Testing, Test Driven Development and the Walking Skeleton Seb Rose Twitter: @sebrose Blog: claysnow.blogspot.com E-mail: [email_address] Phone: 01721 788178
    2. 2. Agenda <ul><li>Introduction </li></ul><ul><li>GOOS </li></ul><ul><li>Walking Skeleton </li></ul><ul><li>Test Driven Development </li></ul><ul><li>Unit Testing </li></ul><ul><li>Myths </li></ul><ul><li>Wrap up </li></ul>
    3. 3. Don’t we all know enough about testing? <ul><li>Lots of software has insufficient automated testing </li></ul><ul><ul><li>How much manual testing goes on at YOUR workplace? </li></ul></ul><ul><li>Testing is still seen as a 2 nd class activity </li></ul><ul><ul><li>What do YOU drop when you’re under time pressure? </li></ul></ul><ul><li>Tests are often written after the code </li></ul><ul><ul><li>Is YOUR code always testable? </li></ul></ul><ul><li>Plenty see tests as a drag on development </li></ul><ul><ul><li>Do your tests inhibit changes to YOUR architecture? </li></ul></ul><ul><li>Not everyone cares about all the tests </li></ul><ul><ul><li>Does everyone run YOUR tests every check-in? </li></ul></ul><ul><ul><li>Who cares when YOUR tests break? </li></ul></ul>
    4. 4. Agenda <ul><li>Introduction </li></ul><ul><li>GOOS </li></ul><ul><li>Walking Skeleton </li></ul><ul><li>Test Driven Development </li></ul><ul><li>Unit Testing </li></ul><ul><li>Myths </li></ul><ul><li>Wrap up </li></ul>
    5. 5. One book to rule them all? <ul><li>Pulls together current thinking </li></ul><ul><ul><li>Walking skeleton </li></ul></ul><ul><ul><li>Acceptance Test Driven Development </li></ul></ul><ul><ul><li>Test Driven Development </li></ul></ul><ul><li>Includes OO design philosophy </li></ul><ul><ul><li>Ports and connectors </li></ul></ul><ul><ul><li>Small decoupled classes </li></ul></ul><ul><ul><li>Do not Repeat Yourself </li></ul></ul><ul><ul><li>Tell, don’t ask </li></ul></ul><ul><li>Worked example </li></ul>
    6. 6. DISCLAIMER <ul><li>I am not affiliated to Freeman/Pryce </li></ul><ul><li>I have never worked with them </li></ul><ul><li>I barely know them </li></ul><ul><li>The book stands on its own </li></ul><ul><li>Mailing list: growing-object-oriented-software@googlegroups.com </li></ul>
    7. 7. Agenda <ul><li>Introduction </li></ul><ul><li>GOOS </li></ul><ul><li>Walking Skeleton </li></ul><ul><li>Test Driven Development </li></ul><ul><li>Unit Testing </li></ul><ul><li>Myths </li></ul><ul><li>Wrap up </li></ul>
    8. 8. What is a walking skeleton? <ul><li>Automatically buildable </li></ul><ul><li>Automatically deployable </li></ul><ul><li>Automatically testable </li></ul><ul><li>No functionality required </li></ul><ul><li>Initial architecture </li></ul>
    9. 9. Why start with the skeleton? <ul><li>The infrastructure of build, deploy, test can be time consuming to implement </li></ul><ul><ul><li>You WILL need it, so do it first </li></ul></ul><ul><ul><li>If you don’t do it now, WHEN will you have time? </li></ul></ul><ul><li>The skeleton gives early visibility </li></ul><ul><li>Without a skeleton it is hard to drive development OUTSIDE-IN </li></ul><ul><ul><li>Acceptance Test Driven Development (ATDD) is a powerful tool </li></ul></ul>
    10. 10. Acceptance Test Driven Development <ul><li>Document functionality using acceptance tests </li></ul><ul><li>Tests readable by ‘business people’ </li></ul><ul><ul><li>FIT / Fitnesse </li></ul></ul><ul><ul><li>Cucumber </li></ul></ul><ul><li>Can replace specifications / user stories in some environments. </li></ul><ul><li>Needs commitment from whole organisation </li></ul>
    11. 11. Red, Green, Refactor
    12. 12. Agenda <ul><li>Introduction </li></ul><ul><li>GOOS </li></ul><ul><li>Walking Skeleton </li></ul><ul><li>Test Driven Development </li></ul><ul><li>Unit Testing </li></ul><ul><li>Myths </li></ul><ul><li>Wrap up </li></ul>
    13. 13. What is TDD? <ul><li>Test Driven Development </li></ul><ul><ul><li>aka Test Driven Design </li></ul></ul><ul><li>A software development practice </li></ul><ul><ul><li>Popularised by agile processes (like XP) </li></ul></ul><ul><li>A development process that generates, among other things, (automated) unit tests </li></ul><ul><li>TDD is NOT a replacement for system/integration testing. </li></ul>
    14. 14. The basics <ul><li>Write a failing test </li></ul><ul><li>Write just enough code to make it pass </li></ul><ul><li>Refactor </li></ul><ul><li>Repeat </li></ul>
    15. 16. When does unit testing become TDD? <ul><li>The test is written BEFORE the code </li></ul><ul><li>The test is RUN before the code is written </li></ul><ul><li>The test must FAIL </li></ul><ul><li>The code is written to SATISFY the test </li></ul><ul><li>Code is ONLY written to satisfy a test </li></ul><ul><li>Run all tests </li></ul><ul><li>The tests must PASS </li></ul><ul><li>REFACTOR the code & tests to production quality </li></ul><ul><li>Ensure all tests still pass </li></ul><ul><li>Remember TDD code must be of PRODUCTION QUALITY </li></ul>
    16. 17. TDD and “agile” <ul><li>Agile Manifesto: </li></ul><ul><ul><li>Individuals and interactions over processes and tools </li></ul></ul><ul><ul><li>Working software over comprehensive documentation </li></ul></ul><ul><ul><li>Customer collaboration over contract negotiation </li></ul></ul><ul><ul><li>Responding to change over following a plan </li></ul></ul><ul><li>TDD is one of several agile practices </li></ul><ul><ul><li>“Agile practices are not optional” – Mike Kohn </li></ul></ul>
    17. 18. Emergent design <ul><li>Big Up Front Design impedes delivery of working code, but </li></ul><ul><ul><li>Initially it’s uncomfortable working without BUFD </li></ul></ul><ul><ul><li>Planning & partitioning work is harder </li></ul></ul><ul><li>Architecture still important </li></ul><ul><ul><li>Walking skeleton – initial application architecture </li></ul></ul><ul><ul><li>Intentional – deliberate conscious decisions </li></ul></ul><ul><li>Rework is inevitable </li></ul><ul><ul><li>TDD makes refactoring less error prone </li></ul></ul><ul><ul><li>BUT since tests are of ‘production’ quality this is cheap </li></ul></ul>
    18. 19. Executable Documentation <ul><li>Prefer documenting your design in tests </li></ul><ul><ul><li>Documentation can often be out of date </li></ul></ul><ul><ul><li>Comments can often be out of date </li></ul></ul><ul><ul><li>Tests run with every build, so CANNOT be broken </li></ul></ul><ul><li>Not an excuse for NO documentation </li></ul><ul><ul><li>Architecture </li></ul></ul><ul><ul><li>Vision </li></ul></ul><ul><ul><li>Scenarios/Use cases/Competencies </li></ul></ul><ul><li>More confidence in documentation that can be verified automatically </li></ul><ul><ul><li>i.e. tests </li></ul></ul>
    19. 20. Challenges <ul><li>At first I found that: </li></ul><ul><ul><li>Working without detailed designs was uncomfortable </li></ul></ul><ul><ul><li>Writing tests first was unnatural </li></ul></ul><ul><ul><li>Ensuring testability was confusing </li></ul></ul><ul><ul><li>Productivity decreased </li></ul></ul><ul><li>Over time I noticed that: </li></ul><ul><ul><li>The tests gave me confidence </li></ul></ul><ul><ul><li>New habits became familiar </li></ul></ul><ul><ul><li>Defects and regressions decreased </li></ul></ul>
    20. 21. For TDD to work <ul><li>Tests need to be easy to run </li></ul><ul><ul><li>All developers and build processes need to run them </li></ul></ul><ul><li>Tests need to be fast to run </li></ul><ul><ul><li>Ran every few minutes or seconds </li></ul></ul><ul><ul><li>Partition test suites to keep fast </li></ul></ul><ul><li>Build needs to be quick </li></ul><ul><ul><li>Partition application to keep fast </li></ul></ul><ul><li>Test failures need to be handled </li></ul><ul><ul><li>Process </li></ul></ul><ul><ul><li>Team commitment </li></ul></ul>
    21. 22. Stop Press: “TDD no substitute for testing” <ul><li>TDD relies on Unit Tests </li></ul><ul><ul><li>aka Developer Tests </li></ul></ul><ul><li>Unit Tests: </li></ul><ul><ul><li>Document the code </li></ul></ul><ul><ul><li>Can’t become out of date </li></ul></ul><ul><ul><li>Well structured (like production code) </li></ul></ul><ul><ul><li>Don’t cover traditional “test team” scenarios </li></ul></ul><ul><li>Testing is just as important as ever </li></ul><ul><ul><li>Integration, System, Acceptance etc. </li></ul></ul>
    22. 23. TDD summary <ul><li>TDD is a DEVELOPER activity </li></ul><ul><li>It delivers: </li></ul><ul><ul><li>(Automatically) Testable software </li></ul></ul><ul><ul><li>Higher test coverage </li></ul></ul><ul><ul><li>Lower defect rates </li></ul></ul><ul><ul><li>Reliable refactoring </li></ul></ul><ul><li>TDD is not a replacement for integration or system testing </li></ul>
    23. 24. Agenda <ul><li>Introduction </li></ul><ul><li>GOOS </li></ul><ul><li>Walking Skeleton </li></ul><ul><li>Test Driven Development </li></ul><ul><li>Unit Testing </li></ul><ul><li>Myths </li></ul><ul><li>Wrap up </li></ul>
    24. 25. What is Unit Testing? <ul><li>A unit test </li></ul><ul><li>isolates a part of the program </li></ul><ul><li>tests a single behaviour </li></ul><ul><li>clearly identifies any reason for failure </li></ul><ul><li>documents expected behaviour </li></ul><ul><li>runs quickly </li></ul>
    25. 26. No free lunch <ul><li>Writing unit tests takes time and skill </li></ul><ul><li>Refactoring unit tests takes time and skill </li></ul><ul><li>Running unit tests takes time </li></ul><ul><li>Interpreting unit test failures takes time and skill </li></ul><ul><li>Fixing defects takes time and skill </li></ul><ul><li>Fixing defects early costs less than fixing them late “ Unit Testing is the most cost effective testing activity you can do. Defects removed in Unit Testing cost around 10 times less than defects removed in Functional verification and around 40 times less than defects removed by Systems or Integration testing.” </li></ul>
    26. 27. Testability <ul><li>Testability needs to be designed in </li></ul><ul><ul><li>TDD ensures code is testable </li></ul></ul><ul><li>Code with hidden dependencies is hard to test </li></ul><ul><ul><li>Dependency Injection/Inversion </li></ul></ul><ul><ul><ul><li>Pass dependencies into code under test </li></ul></ul></ul><ul><ul><ul><li>Write factories that permit injection of test doubles </li></ul></ul></ul><ul><ul><li>Interfaces should be cohesive </li></ul></ul><ul><ul><ul><li>Wide interfaces encourage unnecessary coupling </li></ul></ul></ul><ul><ul><li>Avoid globals, singletons etc. </li></ul></ul><ul><li>Retro-fitting unit tests is hard </li></ul><ul><ul><li>Take small steps </li></ul></ul><ul><ul><li>Introduce a ‘seam’ – c.f. Working Effectively with Legacy Code </li></ul></ul>
    27. 28. A test is not a unit test if: <ul><li>It talks to the database </li></ul><ul><li>It communicates across the network </li></ul><ul><li>It touches the file system </li></ul><ul><li>It can’t run at the same time as other unit tests </li></ul><ul><li>You have to do special things to your environment (such as editing config files) to run it </li></ul><ul><li>(Michael Feathers’ blog, 2005) </li></ul>
    28. 29. Necessity <ul><li>Test observable behaviour </li></ul><ul><ul><li>Don’t modify encapsulation to aid testing </li></ul></ul><ul><ul><li>If a behaviour isn’t observable through the public interface what is it for? </li></ul></ul><ul><li>Don’t slavishly write one test per method </li></ul><ul><ul><li>Test behaviours </li></ul></ul><ul><ul><li>Some methods may not need any dedicated tests </li></ul></ul><ul><ul><li>Methods that implement useful behaviours may need many tests </li></ul></ul><ul><li>Choose test variants carefully </li></ul><ul><ul><li>Edge conditions </li></ul></ul><ul><ul><li>Invalid inputs </li></ul></ul><ul><ul><li>Multiple invocations </li></ul></ul><ul><ul><li>Assert invariants </li></ul></ul><ul><ul><li>Error signalling </li></ul></ul>
    29. 30. Granularity <ul><li>Test a SINGLE observable behaviour </li></ul><ul><ul><li>It is tempting to combine related behaviours in a single test – DON’T </li></ul></ul><ul><ul><ul><li>… even if EXACTLY the same steps are needed </li></ul></ul></ul>public void shouldSortTwoStringsAndReportCorrectSize() { SortedSet<String> animals = new TreeSet<String>(); animals.add(“Zebra”); animals.add(“Anteater”); assertEquals(2, animals.size()); assertEquals(“Anteater”, animals.first()); assertEquals(“Zebra”, animals.last()); }
    30. 31. Understandability <ul><li>Test a single observable behaviour (again) </li></ul><ul><li>Name tests to describe the behaviour under test </li></ul><ul><ul><li>Describe nature of the test </li></ul></ul><ul><ul><ul><li>Is it checking that preconditions are enforced? </li></ul></ul></ul><ul><ul><ul><li>Is a dependency going to signal an error? </li></ul></ul></ul><ul><ul><li>Long names are fine – you only type them once </li></ul></ul><ul><ul><li>Be precise </li></ul></ul><ul><ul><ul><li>shouldReturnCorrectValue is not a good name for a test </li></ul></ul></ul><ul><ul><ul><li>shouldReturnCorrectSumOfTwoIntegersWithoutOverflow </li></ul></ul></ul><ul><ul><ul><li>should_return_correct_sum_of_two_integers_without_overflow </li></ul></ul></ul><ul><li>When a test fails you want to know WHAT WENT WRONG </li></ul><ul><ul><li>You don’t want to reverse engineer the test </li></ul></ul><ul><ul><li>You don’t want to run smaller tests to isolate the failure </li></ul></ul>
    31. 32. Maintainability <ul><li>Unit Tests should be written to same quality as Production code </li></ul><ul><ul><li>Tests will be maintained and read just as often as production code </li></ul></ul><ul><ul><li>Code is communication to other developers not just a compiler </li></ul></ul><ul><li>Organise tests into cohesive suites </li></ul><ul><li>Refactor tests to avoid duplication </li></ul><ul><ul><li>Use suites to perform common set up/tear down operations </li></ul></ul><ul><ul><li>Extract common code into methods </li></ul></ul><ul><ul><li>Extract common functionality into classes </li></ul></ul><ul><li>Remove redundant tests </li></ul>
    32. 33. Reiteration: 5 -ities <ul><li>Testability </li></ul><ul><li>Necessity </li></ul><ul><li>Granularity </li></ul><ul><li>Understandability </li></ul><ul><li>Maintainability </li></ul><ul><li>MUNGT ? </li></ul><ul><li>TeNGUM? </li></ul>
    33. 34. Tests can only be run once they have been written <ul><li>Resist pressure to add unit tests ‘later’ </li></ul><ul><ul><li>Untested code should not be committed to codebase </li></ul></ul><ul><ul><li>How can you know code is testable? </li></ul></ul><ul><ul><li>There are always more pressing things to do tomorrow </li></ul></ul><ul><ul><li>“ Legacy code is code without unit tests” – Michael Feathers </li></ul></ul><ul><li>Keep tests in same changeset as functionality they test </li></ul><ul><ul><li>Aids traceability and auditing </li></ul></ul><ul><li>Subject tests to same quality control as production code </li></ul><ul><ul><li>Apply usual coding standards </li></ul></ul><ul><ul><li>Buddy check/peer review should examine completeness of tests </li></ul></ul>
    34. 35. Tests are only useful when they are run <ul><li>Run the tests automatically </li></ul><ul><ul><li>Developer builds should run them while writing code </li></ul></ul><ul><ul><li>Continuous Integration server builds should run them </li></ul></ul><ul><ul><li>Release/nightly builds should run them </li></ul></ul><ul><li>Test failure == build failure </li></ul><ul><ul><li>At each stage of the process, fail the build if a test is broken </li></ul></ul><ul><ul><li>Failing tests should automatically fail the build </li></ul></ul><ul><ul><li>Automatic notification necessary </li></ul></ul><ul><li>Respond quickly </li></ul><ul><ul><li>Fixing a failed test is highest priority </li></ul></ul><ul><ul><li>Responsibility of whole team </li></ul></ul><ul><ul><li>Resist pressure for “just for now” fix </li></ul></ul>
    35. 36. Demonstrate value of unit tests <ul><li>Unit testing takes time, up front </li></ul><ul><ul><li>Lots of evidence that it saves time later on </li></ul></ul><ul><ul><li>Still need to demonstrate that its working in your team </li></ul></ul><ul><li>Collect metrics now (some suggestions) </li></ul><ul><ul><li>Coverage - how much code is tested? </li></ul></ul><ul><ul><li>Defects per feature </li></ul></ul><ul><ul><li>Regressions per iteration </li></ul></ul><ul><ul><li>Velocity </li></ul></ul><ul><li>Collect metrics continuously </li></ul><ul><ul><li>Integrate collection with your process </li></ul></ul><ul><ul><li>Publish trends </li></ul></ul><ul><ul><li>Expect a learning curve </li></ul></ul>
    36. 37. Agenda <ul><li>Introduction </li></ul><ul><li>GOOS </li></ul><ul><li>Walking Skeleton </li></ul><ul><li>Test Driven Development </li></ul><ul><li>Unit Testing </li></ul><ul><li>Myths </li></ul><ul><li>Wrap up </li></ul>
    37. 38. A few myths I hope I’ve dispelled <ul><li>“Testing is a job for testers” </li></ul><ul><li>“Now that we ‘do’ TDD we don’t need any testers” </li></ul><ul><li>“Tests are only important while the code is being written” </li></ul><ul><li>“Tests aren’t as important as production code” </li></ul><ul><li>“What does it matter what I call it? It’s only a test!” </li></ul><ul><li>“Why should I fix it? It’s not my code!” </li></ul><ul><li>“We can always add the tests next iteration” </li></ul><ul><li>“There’s not enough time to write tests” </li></ul>
    38. 39. Agenda <ul><li>Introduction </li></ul><ul><li>GOOS </li></ul><ul><li>Walking Skeleton </li></ul><ul><li>Test Driven Development </li></ul><ul><li>Unit Testing </li></ul><ul><li>Myths </li></ul><ul><li>Wrap up </li></ul>
    39. 40. Questions? <ul><li>Most of the information from this session can also be found in: </li></ul><ul><ul><li>“ Testing Times” </li></ul></ul><ul><ul><li>published this month in C Vu, the magazine of ACCU </li></ul></ul><ul><ul><li>www.accu.org </li></ul></ul><ul><li>Contact me: </li></ul><ul><ul><li>[email_address] </li></ul></ul><ul><ul><li>@sebrose </li></ul></ul><ul><ul><li>01721 788178 </li></ul></ul><ul><ul><li>claysnow.blogspot.com </li></ul></ul>
    40. 41. References <ul><li>Growing Object-Oriented Software Guided by Tests – Freeman/Pryce </li></ul><ul><li>Bridging the communications gap – Gojko Adzic </li></ul><ul><li>Fit for developing software – Mugridge/Cunningham </li></ul><ul><li>Test Driven Development - Kent Beck </li></ul><ul><li>Working Effectively with Legacy Code – Michael Feathers </li></ul><ul><li>Succeeding with Agile – Mike Cohn </li></ul><ul><li>Refactoring: Improving the Design of Existing Code – Martin Fowler </li></ul><ul><li>Clean code – Robert Martin </li></ul><ul><li>JUnit Recipes – J.B. Rainsberger </li></ul><ul><li>xUnit Test Patterns – Gerard Meszaros </li></ul>