Adjust design to get green bar

pragmatic programmer

pragmatic programmer
pragmatic programmer

A while ago I read the pragmatic programmer. In the book are many tips listed. In the back of the book there is an tear-out card with all the tips collected. As I’m working on different locations all the time I rarely look at the card. The tips however seem very useful to me. Therefore I created a small Google App engine application that sends me a random tip every day. TDD-ing my way through the requirements I now get a tip every day. During the development I ran into one little problem with stubbing my randomizer method.

For the unit-tests testing sending the mail I needed to stub the random result to give a certain result. So I could check that the rest was working. For mocking & stubbing I use Mockito. The normal way you stub a method in a class is to create a mock version of the class and use the when-then pattern as documented over here. The problem I had was however that the method getting the random result was part of the class under test. This resulted in the test failing because sending the mail was never being executed as it was a Mock. Please see the code below:

public class TipRepository {
    ...
    public String randomTip() {
        return tips[getRandomNumber()];
    }

    private int getRandomNumber() {
        return (int)Math.round(Math.random() * (tips.length-1));
    }
}

And the test looked like this:

public RepositoryTest() {
    @Test
    public void randomTestShouldReturnExpectedTip() {
        TipRepository tipRepo = mock(TipRepository.class);
        when(tipRepo.getRandomNumber()).thenReturn(0);
        assertEquals(tipRepo.randomTip(),"sometip")
    }

}

Please note that I use TestNG as testing framework. In TestNG the expected and actual result are reversed if you compare it to JUnit.

So all my tests where failing. In order to get a green bar again I need to adjust my code to be able to test it. After a lot of thought I created an extra class that contains only the randomizer method to pass it into the repository as a dependency.

public class TipRepository {
    private Randomizer randomizer;
    ...

    public TipRepository(Randomizer randomizer) {
        this.randomizer = randomizer;
    }

    public String randomTip() {
        return tips[randomizer.randomNumber(tips.length-1)];
    }
}
public class Randomizer() {
     public int getRandomNumber(int maxValue) {
        return (int)Math.round(Math.random() * maxValue);

    }
}

And the test now looks like this:

public RepositoryTest() {

    @Test
    public void randomTestShouldReturnExpectedTip() {
        Randomizer randomizer = mock(Randomizer.class);
        TipRepository repository = new TipRepository(randomizer);
        when(randomizer.getRandomNumber(2)).thenReturn(1);
        assertEquals(repository.randomTip(), "some tip");
    }
}

Of course you can argue that getting a random number is not the responsibility of the Repository and that therefore the new design is better. But in the old situation the random number was coming from the Java API. Therefore it was not a responsibility of the Repository either. I’m happy to have a green bar now, but I don’t like changing the code just for the tests to be passing. Please let me know your thoughts in the comments or via Twitter.


One response to “Adjust design to get green bar”

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.