Test Driven Development: Are Tests Really Written Before Production Code

Posted on Posted in programming

Let’s say that you do the test driven development. When you have to implement a new functionality, you begin with adding a new test for the new functionality. Then you run all tests and only the new test should fail. Then you write a production code so that the new test passes. Then again you run all tests and all tests pass. Then you refactor the production code and start again with the first step.

What do you do, when you want to refactor a test code or when tests are to slow and you want to speed them up? The test code does not have tests. The production code is not a test code for the test code. If you can’t refactor effectively, how can you change the implementation of tests when you optimize tests for a speed?

Let’s look an example of implementing a functionality that sums two integers. Example has three iterations consisted from four steps. Refactor step is skipped.

1. step: add a test, assert that the method exists

@Test
public void sum_methodExists() throws Exception {
    Calculator calculator = new Calculator();
    assertThat(calculator.sum(1, 1)).isNotNull();
}

2. step: run all tests, only the new test fails

Error:(18, 30) java: cannot find symbol
  symbol:   method sum(int,int)
  location: variable calculator of type com.programbuddy.calculator.Calculator

3. step: write the production code

public int sum(int a, int b) {
    return 0;
}

4. step: run all tests, all tests passes

1. step: add a test, assert that 1 + 1 = 2

@Test
public void sum_twoConcreteNumbers() throws Exception {
    Calculator calculator = new Calculator();
    assertThat(calculator.sum(1, 1)).isEqualTo(2);
}

2. step: run all tests, only the new test fails

org.junit.ComparisonFailure: 
Expected :2
Actual   :0
 <Click to see difference>

3. step: write the production code

public int sum(int a, int b) {
    return 2;
}

4. step: run all tests, all tests passes

1. step: add a test, assert that sum of the first 99 natural numbers is 100 * 99 / 2

@Test
public void sum_first99Numbers() throws Exception {
    Calculator calculator = new Calculator();
    int i = 1;
    int j = 0;
    for (; i < 100; i++) {
        j = calculator.sum(j, i);
    }
    assertThat(j).isEqualTo(100 * 99 / 2);
}

2. step: run all tests, only the new test fails

org.junit.ComparisonFailure: 
Expected :4950
Actual   :2
  <Click to see difference>

3. step: write the production code

public int sum(int a, int b) {
    return a + b;
}

4. step: run all tests, all tests passes

In test driven development, when you write a test before a new production code is written, you have a one time opportunity. You get verification that the test tests the new production code. The problem is that this happens only at one moment in time. If you write a test after you write a production code, you can not use this technique for verification.

Let’s say that you will write a test only before you need to implement a new functionality and you will do this in test driven way. In short, you write a test before you write a production code. This means that you will never change the existing tests. You can only delete tests or add a new test for a new functionality. If you change an existing test, it will be the same as if you write a test after an implementation is done.

Back to example, let’s change the implementation of the last test. The test code will be shorter and more clear.

@Test
public void sum_first99Numbers() throws Exception {
    Calculator calculator = new Calculator();
    OptionalInt sum = IntStream.rangeClosed(1, 99).reduce(calculator::sum);
    assertThat(sum.getAsInt()).isEqualTo(100 * 99 / 2);
}

How do you know that the new test tests the same thing as the old test? This test is a new test and the production code already exists. You will use same techniques for verification as when you write a test after a production code is written.

Conclusion

Do we need to maintain a test code?

  • Maybe you prefer to write new tests for a new functionality or for a newly discovered bug rather than you refactor or rewrite old tests.
  • During a long period of time tests will be added and some tests will be removed, because a new production code will be written and an old production code will be removed. New tests will probably be better written as old tests.

Are tests really written before production code in test driven development?

  • It depends on you. Pay attention, if existing tests are changed after a production code is written.

Do we need good techniques for testing?

  • If you encounter an application that does not have tests for some functionalities, how do you know how the application works. You test it.

Leave a Reply