“Les doutes, c’est ce que nous avons de plus intime.”
Albert Camus.
Building software, following the principles of TDD (Test-Driven Development) will help to assure the quality along all the development process and complemented with Integration Test, and Continuous Integration, good practices and methodology. This posts is intended to explain this subject.
Software development is not only developing a set of functionality but also deliver a software that match quality requirements. But, What’s is quality? Here a random definition of quality: “In business, engineering, and manufacturing, quality has a pragmatic interpretation as the non-inferiority or superiority of something; it’s also defined as being suitable for its intended purpose (fitness for purpose) while satisfying customer expectations. “(Source : Wikipedia). Let’s keep the concept of “satisfying customer expectations” to explain later the concept of TDD (Test-Driven Development). A “customer” expects from the “software” a set of functionality to accomplish a specific task, if the functionality is suitable for the intended functionality : following this premise this is what we could call quality.
I have a problem with this definition of quality, first because is a static definition, and secondly because a “customer” expectation never ends up. Let me explain me this. Interaction between the customer and the software application evolves in the time in function of the requirement of the client. Customer requirements evolves and change all the time, quality definition in this dynamic interaction is the reactivity of the software application to deliver in a suitable way the functionality on demand.
“Test-development driven” is a methodology to deliver software linking “quality” and “change”, that is the add value in this practice. The implementation of this methodology is of a awesome simplicity : this is implemented using “an assessment intended to measure the respondents’ knowledge or other abilities”, this is called “Test”.
TDD ask you to write the test before the code implementation (Code Clean pp 122).
Hands-on!
Practical case: <Implement a software that execute for 2 integers these 4 operations >:
- Addition
- Subtraction
- Multiplication
- Division (Round to the lower Integer)
First Step : Your step must fail
Let’s write our first test for the Addition.
import org.junit.Assert;
import org.junit.Test;
public class CalculatorTest {
@Test
public void addition() {
Calculator calculator = new Calculator();
Integer result = calculator.addition(7, 3);
Assert.assertTrue(result == 10);
}
}
An object Calculator exposes a method addition
public class Calculator {
public Integer addition(int i, int j) {
//no implementation for this test
throw new NotImplementedException();
}
}
Run the test addition. Must fail

Second Step : Implementation, your test must pass
At this point you must complete the method “addition”, in this case is quite obvious, i.e.:
public class Calculator {
public Integer addition(int i, int j) {
return i + j;
}
}

Third Step : Repeat step 1 & step 2 for the other operations
Your code at this point must look like this.
import org.junit.Assert;
import org.junit.Test;
public class CalculatorTest {
@Test
public void addition() {
Calculator calculator = new Calculator();
Integer result = calculator.addition(7, 3);
Assert.assertTrue(result == 10);
}
@Test
public void substraction() {
Calculator calculator = new Calculator();
Integer result = calculator.substraction(7, 3);
Assert.assertTrue(result == 4);
}
@Test
public void multiplication() {
Calculator calculator = new Calculator();
Integer result = calculator.multiplication(7, 3);
Assert.assertTrue(result == 21);
}
@Test
public void division() {
Calculator calculator = new Calculator();
Integer result = calculator.division(7, 3);
Assert.assertTrue(result == 2);
}
}
All your tests a passing

Analysis of existing code
At this point the application provide the functionality required for the client. The tests are OK. Let’s see closely the code written and let see the architecture so far.
There is only 1 object “Calculator” that encapsules all the operations ,this design “simple” will be the source of problems and headaches in a very short horizon. Why? At first place, an object in the system must have only one responsibility, and must be a single point for a vector of functionality in whole the system. This concept is know like “Single responsibility principle SRP”. You can find this concept large explained in different sites. I am more interested in another concept that allows SRP, is empowerment, or delegation of responsibility. In another words identify the vectors and isolate them in singles objects. For our case


At the beginning of any software project the functionality borders are not clearly defined, creating small/lights objects with a single functional value, add flexibility to the architecture. This approach assures the resilience in the final design.
Let’s apply TDD to disaggregate the responsibility from the object “Calculator”
public class Addition {
public Integer operation(int i, int j) {
return i + j;
}
}
public class Division {
public Integer operation(int i, int j) {
return i/j;
}
}
public class Multiplication {
public Integer operation(int i, int j) {
return i*j;
}
}
public class Substraction {
public Integer operation(int i, int j) {
return i-j;
}
}
In the same order, our unit tests will be modified to support this refactoring. The object Calculator can be deleted.
Remember to run the test cases after the refactoring

Abstractions
Abstractions are flexible structures that help reshape the design of the software in a clean way not only in the disagragation of responsibilities. Abstractions are perfect to isolate functionality and allow unit or integration tests (mock) etc.
In Java or CSharp this abstractions could be <<Interfaces>> or <<Abstract>> classes.
All the object implement an “operation”. The signature is the same for all these object. We reduce the “weight” of each object is we make an higher abstraction around the existing objects.

Here the implementation
public interface Operation {
public Integer operation(int a, int b);
}
public class Addition implements Operation {
public Integer operation(int i, int j) {
return i + j;
}
}
public class Division implements Operation {
public Integer operation(int i, int j) {
return i/j;
}
}
public class Multiplication implements Operation {
public Integer operation(int i, int j) {
return i*j;
}
}
public class Substraction implements Operation {
public Integer operation(int i, int j) {
return i-j;
}
}
Once again verify if the implementation is correct. Run the unit test cases again
Conclusions
- TDD allows us modify our design of software. In software, modifying and redefining a software is a normal process in the life cycle of the product : the process is called refactoring. So TDD is permanent process, only it stops when the software is deprecated.
- Single functional vectors in a system (SRP) helps to reshape and maintain the code easily even when the functional borders are not clearly defined by the client. Having small and light structures with low logic capacity make us possible change fast and with low impact in the whole system.
- Abstractions are structure that have a lot of advantages :
- allows to implement design more lose coupled,
- when you design evolve you can modify your “contract/interfaces” and control the consistency of your design in the object that implement your abstraction
- You can use more complex test using Mocks
