| I have a pragmatic approach to TDD, i.e. it doesn't practically matter if you write the code or tests first as long as the relevant code has tests: 1. write the test code first (possibly with a skeleton implementation) if you want to get an idea/feel for how the class/code is intended to be used; 2. write the code first if you need to; 3. ensure that you have at least one test at the point where the code is mimimally functional. More generally: 1. don't aim for 100% code coverage (around 80-90% should be sufficient); 2. test a representative example and appropriate boundary conditions; 3. don't mock classes/code you control... the tests should be as close to the real thing as possible, otherwise when the mocked code changes your tests will break and/or not pick up the changes to the logic -- Note: if wiring up service classes, try and use the actual implementations where possible; 4. use a fan in/out approach where relevant... i.e. once you have tests for various states/cases in class A (e.g. lexing a number, e.g. '1000', '1e6', '1E6') you only need to test the cases that are relevant to class B (e.g. token types, not lexical variants, e.g. integer/decimal/double); 5. test against publically accessible APIs, etc... i.e. wherever possible, don't test/access internal state; look for/test publically visible behaviour (e.g. don't check that the start and end pointers are equal, check that is_empty() is true and length() is 0) -- Note: testing against internals is subject to implementation changes whereas public API changes should be documented/properly versioned. |