├── README.md └── anti-tdd-influence-diagram.jpeg /README.md: -------------------------------------------------------------------------------- 1 | # Test Driven Development Cheat Sheet 2 | 3 | _Inspired by "Test Driven Development by Examples" - Kent Beck_ 4 | 5 | ## What is TDD? 6 | 7 | Drive your development by tests to reach the goal of having clean code that works. 8 | 9 | **What should I do?** 10 | 11 | 1. **Write a test**: _As simple as possible_ 12 | 2. **Make it run**: _Quick green excuses all sins but only for a moment_ 13 | 3. **Make it right**: _Refactor_ 14 | 15 | **Other XP approaches, TDD relates fine to...** 16 | 17 | - Pair Programming 18 | - Continuous Integration 19 | - Simple Design 20 | - Refactoring 21 | - Continuous Delivery 22 | 23 | ## Strategies to quickly go to green 24 | 25 | - **Fake it** 26 | 27 | Return constants and gradually replace them with working code. 28 | For cases when implementation is not really straightforward. 29 | 30 | - **Obvious Implementation** 31 | 32 | Directly write working code. 33 | In case implementation is straightforward. 34 | 35 | - **Triangulation** 36 | 37 | Write more than one test to verify code is working. 38 | Generally to be used when being unsure of the correctness of the abstraction of the calculation. 39 | 40 | ## How our tests should be? 41 | 42 | - **Fast** 43 | 44 | Our test suite has to perform as quickly as possible. 45 | 46 | - **Isolated** 47 | 48 | Success or failure for test A has to be irrelevant for test B coming after. 49 | No state must be maintained within the test suite. 50 | 51 | - **Small** 52 | 53 | If a test is testing too many things or complex code flows, it requires too much time for the red bar to become green, distracting you and slowing the implementation (and probably the cleanliness of the code). 54 | Difficult testing bits is a design issue and must be solved from a design standpoint. 55 | 56 | - **Specific** 57 | 58 | Avoid ambiguous assertions that allow multiple results to pass the test. 59 | 60 | ## Testing Patterns 61 | 62 | - **One to Many** 63 | 64 | To test collection of objects, first write test for the single object, and then make it work for the collection as well. 65 | 66 | - **Fixtures** 67 | 68 | Common objects needed by multiple tests: define fixtures as subclasses of TestCase. 69 | 70 | - **Step Size** 71 | 72 | You can use tiny steps to go forward with the code, or bigger steps depending on the context (todo things, complexity of the implementation, tiredness…). 73 | 74 | - **Evident data** 75 | 76 | In most cases it is possible to duplicate data within the test to clearly have an idea of how the implementation is expected to work. 77 | Unlikely errors to happen can be tested with “Crash Test Dummy” representing a particular case driving code to errors because of unexpected or weird inputs. 78 | 79 | - Commenting out failing tests is **strictly forbidden**. They must be fixed instead. 80 | 81 | - **Never remove a test** if, by removing it, your confidence decreases. If two tests has the same behavior, but they express two different cases, leave them both. 82 | 83 | ## Refactoring 84 | 85 | - Dogmatic approach for interruptions is not to have interruptions (for instance some fix to apply that you notice while refactoring something else). In practice you can have brief interruptions, but maximum one at a time (not interrupt an interruption…). 86 | 87 | - Use todo list for keeping track of implementations and refactoring activities. 88 | 89 | - Remove duplication between test and code as a way to drive design. 90 | 91 | - When a new defect gets reported, first thing is to write a test representing that failure and then apply the fix that consequently fixes the new failing test as well. 92 | 93 | - **Reconcile differences**: unify two similar pieces of code by adapting one step at a time to bring them closer. 94 | 95 | - **Isolate Change**: modify an existing method, isolate the code that has to be changed and then proceed (see Extract Method, Extract Object and Method Object). 96 | 97 | - **Migrate Data**: to change data being used, duplicate it to the new version, then switch the implementation to the new one instead of the old format and then change the external API. 98 | 99 | - **Extract Method**: a long or complex method has to be split in more pieces of code to be extracted as separate methods. 100 | 101 | - **Extract Interface**: introduce a new operation within an already existing shared object, create a new interface with the new op. 102 | 103 | - **Method Object**: Complex method with many parameters has to be refactored to a new object with its own methods. 104 | 105 | - **Rely on IDEs** refactoring support whenever is possible. 106 | 107 | - **Refactoring** without tests drives to errors. 108 | 109 | ## Stay effective 110 | 111 | - What to test? Always write what you want to test in a list before starting. Never take a step forward without knowing where you’re going. 112 | 113 | - When new ideas arise, keep note of them, but don’t allow them to distract your attention from what you are implementing. 114 | 115 | - Leave the programming session with a broken test so that the next time you get back to the code you know where to start from. When working with a team leave all the tests running, instead. 116 | 117 | - Use nested-level-comments to group tests and identify they’re part of a grouped test case 118 | 119 | - Test code from external providers ONLY if you can’t trust them. 120 | 121 | - Work fresh - If tired or you can’t figure out how to work with a test, take a break. 122 | 123 | ## Yes, but why? Need some motivation... 124 | 125 | - We aren’t striving for perfection. By saying everything two ways - as code and as tests - we hope to reduce our defects enough to move forward with confidence. 126 | 127 | - The goal is to write clean code that works. 128 | 129 | - Design is not done prior the implementation (analysis approach), but while writing tests, minimizing blockers while analyzing. When I'm trying to add some new functionality, I'm not worried about what really makes a good design for this piece of function, I'm just trying to get a test to pass as easily as I can. When I switch to refactoring mode, I'm not worried about adding some new function, I'm just worried about getting the right design. With both of these I'm just focused on one thing at a time, and as a result I can concentrate better on that one thing. 130 | 131 | - Applying design modifications, you don’t have to reason for X minutes to analyze possibilities, but only apply modifications and check whether the tests break. Computer answers in few seconds, when our mind answers in minutes. 132 | 133 | - To eliminate duplication. 134 | 135 | - It shortens the feedback loop over design decisions. 136 | 137 | And check out this influence diagram: 138 | 139 | ![Anti-TDD influence diagram](/anti-tdd-influence-diagram.jpeg) 140 | 141 | _Pressure increases?_ -> **Testing decreases** 142 | 143 | _Testing decreases?_ -> **Errors increase** 144 | 145 | _Errors increase?_ -> **Pressure increases** 146 | 147 | **It becomes a death-spiral.** 148 | 149 | --- 150 | 151 | My notes from Kent Beck's "Test Driven Development by Examples" 152 | -------------------------------------------------------------------------------- /anti-tdd-influence-diagram.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acarbone/TDD-Cheat-Sheet/ba584b8bc4be60b84b0a044a8daf1889d7c77ded/anti-tdd-influence-diagram.jpeg --------------------------------------------------------------------------------