Working with TDD

Best practices, naming conventions, processes to keep in mind, development practices and tools to use for a complete tested/testable environment.

  • Separate implementation from test code
    Benefits: avoids packaging tests together with the production binaries
  • Keep packaging of test classes the same as the unit they’re testing
    Benefits: Helps finding and running tests obviously
    src/main/java/ -> src/test/java/
  • Name test classes similarly to the units they’re testing
    Benefits: Helps finding and running tests obviously
    e.g.: src/main/java/ -> src/test/java/
  • Use descriptive names for test methods
    Benefits: helps understanding the objective of tests, serves as documentation for the implementation being tested
    One of the most used methods is naming them using the Given/When/Then syntax used in Behavioural Driven Development.
  • Write the test before the implementation code (obvious)
    Benefits: ensures that testable code is being written; ensures that every line of code gets tests written for it. By writing or modifying test first, developer is focused on requirements before starting to work on a code.
  • Only write new code when test is failing
    Benefits: confirms that the test does not work without the implementation
  • Rerun all tests every time implementation code changes
    Benefits: ensures that there is no unexpected side-effect caused by code changes. There are the so-called watchers that you turn on when starting with development and runs all tests every time an implementation is added.
  • All tests should pass before a new test is written
    Benefits: focus is maintained on a small unit of work; implementation code is (almost) always in working conditions.
  • As the other rules above this requires refactoring to be done only after all tests are passing
    Benefits: refactoring is safe
  • Write the simplest/smallest code to pass the test
    Benefits: ensures cleaner and clearer design; avoids unnecessary features
  • Write assertions first, act later
    Benefits: tells exactly what the implementation should be about by clarifying the purpose of the requirement and test early
  • Minimize assertions in each test because if it fails it might be hard to find which of the assertions failed in some environments
    Benefits: avoids assertion roulette; allows execution of more asserts.
  • Don’t introduce dependencies in your tests; the execution of your test shoud have no order
    Benefits: tests work in any order independently whether all or only subset is run
  • Use mocks
    Benefits: reduced code dependency; faster tests execution.
  • Use setup and tear-down methods
    Benefits: allows setup and tear-down code to be executed before and after the class or each method.
  • Do not use base classes. It shouldn’t be needed to go to a parent class of a parent class of a test to understand what a test does.
    Benefits: test clarity.
  • Code coverage. Tools like JaCoCo, Clover and Cobertura that scan your project and check for untested methods and units.
    Benefit: assurance that everything is tested.
  • Continuous integration (CI). Huge must in a tested environment. At fixed intervals or at every push to the remote repository the CI application downloads your project builds it and runs all the test. If any of the tests fail, the CI notfies the team. e.g.: Jenkins
    Benefits: Always know ahead if builds are broken

Bonus: There are also tools that change conditional operators, return types, return values and more in your source code and then run all the tests. In this case, all of them are expected to fail, otherwise the test was not written correctly.



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Eni Sinanaj

him/him and stuff… :) Engineer, Business Development, Management, Writer #diy #automation #digitalizationftw