Tag Archives: TDD - Page 2

File Lottery Kata

When I do some coding, I use test driven approach, have lots of fake and mock objects, and I use dependency injection for putting everything together. I usually don’t work alone, and from time to time I have to introduce these methods to someone with less experience in this particular area. Unfortunately, it takes me a lot of time to find the right example for them, because, frankly, the existing solutions are not that lightweight: spring context with configuration, annotations, different mock libraries, or even fake objects where mocking is impossible.

So I came up with a simple code kata exercise, which allows one to

  • practice the usage of dependency injection
  • try out different dependency injection frameworks
  • practice faking and mocking
  • try out different mocking libraries

The kata is quite simple (15 minutes):

Implement an application which follows the iterator design pattern. This particular application receives a directory as argument, and at each consecutive call, it returns a file name from the directory that hasn’t been returned before, in a random order. When the application reaches the end of the content of the directory, it shall start over, again returning the directory contents in a random order. If the directory is empty, then every call shall return an empty string. If the argument is not a directory but a file, then its name shall be returned on each consecutive call.

The random order makes testing the application quite complicated. In order to do proper testing – have an expected random number in each test case – the random generator shall be injected and mocked (or faked). If you find the right way to do it, then this exercise is pretty straightforward.

A very simple solution with fake test objects is available on my github page.

VN:F [1.9.17_1161]
Rating: 0.0/10 (0 votes cast)

Using Kata for Improvements

I used to keep coding dojos for my colleagues, and it was sometimes very hard to find the right topic. I recently rediscovered the code kata – I did it earlier, but stopped after a short period -, and got an idea. I’m going to use it for discovering areas where our teams can improve. The setup is very easy: I propose a certain kata to the others with a time constraint. While they are working – the participation is voluntary -, I’m hanging around and looking for certain clues. These clues and the discussions after the session will help me find the areas where we need to exercise more.

After they get used to the code kata style and are able to finish the exercise within the time frame, we go forward with some constraints. In the far future, they will be able to pick their own code kata and constraint, but first there are things which have to be re-learnt and practised more. Here are some of the usual problems:

  • Too much time spent in red
  • Too much thinking before actually doing something
  • Not following the ideas from the clean code book
  • Too large steps

My plan is to come out with good practices in order to show a way to improve these areas, but for now, let’s have a final look at the code kata setup:

  1. Present a coding exercise for the participants
  2. Give them a time frame and keep them informed about the elapsed time
  3. Walk around and watch out for things the guys are doing right and wrong
  4. When the time has elapsed, shortly discuss the experience, share ideas with each other (sharing is very important here)
  5. If there is time left, redo the session from the start

We are going to keep these sessions twice a week before the daily stand-up meetings. Usually this time of day is less productive, because not everybody is in the office, people are warming up, having their starting tea or coffee – the list goes on. It is also a good time for doing improvements, but I’ll talk about that in a different post.

One can ask why this style is different from others, and how it is going to help. I see it this way: if programmers have to perform a simple but challenging task under time pressure, they are focusing on it very much. They won’t bother that you are watching what they are doing, or that you are asking them short but focused questions. On the other hand, during pair programming, they may show a picture of themselves as they want to look like, or simply become shy. Time will tell how this is going to work. I’ll keep you posted.

VN:F [1.9.17_1161]
Rating: 0.0/10 (0 votes cast)

One Step Back In Testing

There are several advantages and disadvantages of Test Driven Development. In this post, I have no intention of repeating any of these, instead, I’d like to show a way to use TDD effectively while changing legacy code.

The Problem

Have a look at this legacy code:

package com.zsoltfabok.dojo.legacy.stepback;
public class Comparator {
    public boolean same(String string) {
        char[] data = string.toCharArray();
        char[] first = null;
        char[] second = null;
        boolean value = false;
 
        for (int i = 0; i < data.length; i++)
        if (data[i] == ' ') {
            first = new char[i];
            second = new char[data.length - i - 1];
            System.arraycopy(data, 0, first, 0, i);
            System.arraycopy(data, i + 1, second, 0, data.length - i - 1);
            if (first.length == second.length)
                for (int j = 0; j < first.length; j++)
                    if (first[j] == second[j])
                        value = true;
                    else {
                        value = false;
                        break;
                    }
            else
                return false;
            break;
        }
        return value;
    }
}

This code does not do much; it accepts two words separated with a space, and returns true/false depending on whether the words are equal or not. This works quite well, but imagine that we are asked to enhance it, so that the comparison is not case sensitive any more. As a first step, have some test cases in order to preserve the original behaviour:

public class ComparatorTest {
 
    private Comparator comparator = new Comparator();
 
    @Test
    public void shouldReturnTrueForTheSameWords() {
        assertTrue(comparator.same("word word"));
    }
 
    @Test
    public void shouldReturnFalseForDifferentWords() {
        assertFalse(comparator.same("ward word"));
    }
}

There can be more, but for now, they are enough (check the screencast and the source repository for the whole test suite). TDD and the green bar, among other things, make you/me confident that the upcoming changes won’t affect the already implemented behaviour. This is the most important thing in it for me. Now back to the legacy code. Have the test case, which will drive the change:

    @Test
    public void shouldReturnTrueForTheSameButDifferentlyCasedWords() {
        assertTrue(comparator.same("wORd word"));
    }

After having this test case on board, which turns the bar red, the following will happen:

  • introducing the change (implementation of the non case sensitive comparison)
  • massive refactoring (nobody doubts it I assume)

Such a huge work may take “hours” even for that small piece of code above (I admit that in this case it won’t take hours). Obviously, you cannot commit it, cannot ship it to the customer, you cannot show it to others besides your pair, etc. until the change is not done.

Ideas for Solving the Problem

The TDD mantra says red-green-refactorred-green-refactor,… but is does not say anything about the time spent in each phase, a factor that I consider very important. For example, staying too long in green and refactor means less or no progress, staying too long in red means losing control over the code, causing quality and feature degradation. In order to avoid these cases I’ll take two ideas:

The small steps help to make progress in green, and the limited time in red helps to stay on the right track. If you realize after some minutes that you are doing changing and refactoring in one step, you may do your last step back, and perform only one of them. I prefer doing the refactoring first, because the green code is shippable, shareable, and nevertheless I feel more secure, because the test cases prevent me from introducing bugs in the existing functionality. So a third item to the list:

  • take a step back: do the refactoring first and the change afterwards

One can argue that only the change has value to the customer so that shall be done first and refactoring afterwards. In my point of view, this statement highly depends on the definition of value. If the customer got the code, the value wouldn’t only mean the functionality but quality as well. However, I admit that there are cases when the change comes first and refactoring afterwards.

Ignoring Test Cases

One way of stepping back is to ignore the new test case. Do not delete it, just @Ignore it:

    @Ignore("Introduces new functionality, but I must refactor first")
    @Test
    public void shouldReturnTrueForTheSameButDifferentlyCasedWords() {
        assertTrue(comparator.same("wORd word"));
    }

An ignored test case is similar to a TODO note, but a bit more effective. You know that the test case is there, because Eclipse shows the number of ignored test cases. Now everything is green again, you spent less time in red, but need a smaller step. Do the refactoring now. The first test cases make sure that nothing is going to be broken, and with wise refactoring, the introduction of the change will be fast and easy.

When the refactoring is done, remove the @Ignore tag, and introduce the change. You can apply this technique as many times as you want.

Don’t get me wrong, there is nothing wrong with such test cases, on the contrary: they are very good test cases. They not only drive the implementation, but also point out that the code base needs refactoring.

Write Test Cases With Temporarily Wrong Assertion

The example above introduces something new, but sometimes an already existing functionality has to be fixed. Imagine that the customer complains that the method does not work if the input contains trailing spaces. Now, the test case looks like this:

    @Test
    public void shouldReturnTrueInCaseOfSameWordsButWithTrailingSpaces() {
        assertTrue(comparator.same("word word "));
    }

Another way of stepping back is to change the assertion here like this:

    @Test
    public void shouldReturnTrueInCaseOfSameWordsButWithTrailingSpaces() {
        assertFalse(comparator.same("word word "));
    }

This test case provides more safety, because this is how the legacy code works, isn’t it? As soon as the refactoring is done, do not forget to change back to the original test case.

Example

In the following screencast I demonstrate how to use these techniques while working with the example legacy code.

The source code of the example is available on github.

VN:F [1.9.17_1161]
Rating: 0.0/10 (0 votes cast)