Test-driven development is a programming technique in which the validation of the correctness of the source code is implemented before the actual source code itself. This blog post is a summary of the lessons learned from a “Test-driven development with Java” training by lp-it. In order to increase the readability, it also includes some additional research.
Experience is a hard teacher because she gives the test first, the lesson afterward. (Chinese proverb)
In Test-driven development (TDD), the first step of a programmer is to write a failing unit test, a script which makes the absence of a system feature explicit. In the second step the minimum amount of source code is implemented which is needed to fulfil this requirement. The third step is to refactor the implementation. This cycle is intended to be repeated in short iterations of a few minutes.
TDD became popular in around 2002 along with the rise of Extreme Programming and other agile software processes. Today it is successfully applied in big software projects and sold as a best practice by many consulting companies, e.g. it-agile, ThoughtWorks and LeSS.
The application of TDD promises a number of advantages. It helps to:
- get a clear understanding of the requirements
- decompose complex problems
- deliver high quality code even under time pressure
- have regular success experiences.
TDD is not uncontroversial for the following reasons:
- It is counter-intuitive like the Monty Hall Problem.
- It takes about two to three years practice to do it well.
Actually, there are passionate advocates and opponents for this practice in the software community.
The most important lesson for me in the TDD training was, that the testability of the source code can be improved by the application of the following design principles:
|Loose coupling||The dependencies between modules should be minimised.|
|High cohesion||Modules should be grouped by the data they are working with.|
Find more information about this subject using the keywords “SOLID design principles”.
Loose coupling can be achieved by the application of the design pattern Abstract Factory, Bridge, Chain of Responsibility, Command, Facade, Mediator and Observer.
High cohesion can be reached by the application of the refactoring pattern Extract Class, Extract Module, Extract Subclass, Extract Superclass, Pull Up Method, Push Down Method, Pull Up Field, Push Down Field, Move Field and Move Method.
The advantage of training courses over books and videos is, that they can include personalised, practical advice:
- Start working on a ticket by writing unit tests, always.
- Example is better than precept.
- The Boy Scout Rule can help to get started.
- At least 70% of the source code should be covered by unit tests, 80% is very good and more than 95% is perfect.
- TDD should be applied in a pragmatic way and not necessarily by the book.
As TDD is all about writing unit tests, here is an overview of the most commonly used Java tools for testing:
|JUnit||The de-facto standard framework for unit tests.|
|TestNG||An alternative for JUnit.|
|Mockito||A library for the creation of mock and stub objects.|
|EasyMock||An alternative for Mockito.|
|PowerMock||Extends Mockito and Easymock to be able to test untestable code.|
|WireMock||Can be used for stubbing and mocking web services.|
It is a common saying that no complex software system is free from defects. The reason is, that even the best developers sometimes rely on false assumptions. As long as we cannot prove the correctness of our code mathematically, it needs to be tested thoroughly before it can be delivered to the customer. As the release cycles tend to be shorter and shorter, these tests need to be automated. The Test Pyramid model implies that unit tests should be the foundation of the test automation. Whether these tests are written before or after the source code seems to be a matter of taste. Writing the tests first can lead to a number of advantages and from my perspective is thus worth learning.