TDD — Test-driven FizzBuzz

Ronnie Schaniel
7 min readDec 10, 2020

The FizzBuzz task: Write a program that prints the numbers from 1 to 100. But for multiples of 3 print “Fizz” instead of the number and for the multiples of 5 print “Buzz“. For numbers which are multiples of both 3 and 5 print “FizzBuzz”.

Let’s solve this example test-driven in Java using JUnit.

I don’t really want to test the console output (print). So, for simplicity I narrow down the problem. It should not print the numbers, “Fizz”, “Buzz” and “FizzBuzz”, but return the mapped output String for a single input number, e.g. “7” for 7.

Remember TDD, red/green/refactor. We start with a test:

@Test
public void testFizzBuzz() {
assertEquals("1", fizzBuzz(1));
}

We have added our first 4 lines and with that we have already taken some design decisions. The interface to our FizzBuzz program is the fizzBuzz method. It accepts a number as parameter, while returning a String (the single output String for the input number).

With this first test in place, we can run the test:

Red! We get a compilation error. Next step: green. So, let’s take the easiest step to get to green:

@Test
public void testFizzBuzz() {
assertEquals("1", fizzBuzz(1));
}

private String fizzBuzz(int input) {
return "1";
}

And with this we get the desired green bar. So, it’s red to green in a few seconds time.

Refactoring is about removing duplication. Do we have any duplication in that current version? Yes, we have. The “1” is appearing in the test and in the implementation. But, I don’t want to refactor that yet. I want to gather some more information before I decide about the refactoring step.
Let’s add the next test:

@Test
public void testFizzBuzz() {
assertEquals("1", fizzBuzz(1));
assertEquals("2", fizzBuzz(2));
}

Red again! But that’s not so tragic. We gathered additional feedback and have a little bit more information.

Let’s make it green quickly:

@Test
public void testFizzBuzz() {
assertEquals("1", fizzBuzz(1));
assertEquals("2", fizzBuzz(2));
}

private String fizzBuzz(int input) {
return input == 2 ? "2" : "1";
}

Now the duplication bothers me. There it is, only a few characters apart: 2 ? “2”. Easy to spot. So, let’s eliminate it. That means, it’s time for refactoring.

private String fizzBuzz(int input) {
return String.valueOf(input);
}

Still green. So, the refactoring did not break anything. On to the next test. I feel a little bit more confident now. So, let’s take a bigger step (“Fizz” for multiples of 3 it says):

@Test
public void testFizzBuzz() {
assertEquals("1", fizzBuzz(1));
assertEquals("2", fizzBuzz(2));
assertEquals("Fizz", fizzBuzz(3));
assertEquals("Fizz", fizzBuzz(6));
assertEquals("Fizz", fizzBuzz(9));
}

A little bit of modulo and we are back to green:

private String fizzBuzz(int input) {
if (input % 3 == 0) {
return "Fizz";
}
return String.valueOf(input);
}

If “Fizz” for 3’s is that easy, “Buzz” for 5’s should not be difficult. Red:

@Test
public void testFizzBuzz() {
assertEquals("1", fizzBuzz(1));
assertEquals("2", fizzBuzz(2));
assertEquals("Fizz", fizzBuzz(3));
assertEquals("Fizz", fizzBuzz(6));
assertEquals("Fizz", fizzBuzz(9));
assertEquals("Buzz", fizzBuzz(5));
assertEquals("Buzz", fizzBuzz(10));
}

Green:

private String fizzBuzz(int input) {
if (input % 3 == 0) {
return "Fizz";
}
if (input % 5 == 0) {
return "Buzz";
}
return String.valueOf(input);
}

Refactor, still green:

private String fizzBuzz(int input) {
if (isDivisibleBy(input, 3)) {
return "Fizz";
}
if (isDivisibleBy(input, 5)) {
return "Buzz";
}
return String.valueOf(input);
}

private boolean isDivisibleBy(int dividend, int divisor) {
return dividend % divisor == 0;
}

A little experiment done. We removed a duplication, but had to introduce another method. Thanks to the test, we had quick feedback. But do we really want this change? Is it a good design? For me the % operator is well readable and understood. So let’s revert. I like this more:

private String fizzBuzz(int input) {
if (input % 3 == 0) {
return "Fizz";
}
if (input % 5 == 0) {
return "Buzz";
}
return String.valueOf(input);
}

Now let’s take care of: For numbers which are multiples of both 3 and 5 return “FizzBuzz”. I ignored that up to now. I wanted to start with the easy outputs, on something I know more or less how to solve. This allowed me to focus.

How do we take care of “FizzBuzz”? It seems more complicated, how should we implement that? That is a problem for a later point in time (in a few seconds). What comes first: Writing a test.

assertEquals("FizzBuzz", fizzBuzz(15));

Red because it returns “Fizz” instead of “FizzBuzz”. We remember that “Fizz” is returned for multiples of 3. So, the test is telling us that we need to have a look at the logic that returns the “Fizz” because of the 3. That’s a start. More information for the implementation than we had a few seconds ago. So, we know that we have to take care of this 15 before the “Fizz” logic comes into play:

private String fizzBuzz(int input) {
if (input % 3 == 0 && input % 5 == 0) {
return "FizzBuzz";
}
if (input % 3 == 0) {
return "Fizz";
}
if (input % 5 == 0) {
return "Buzz";
}
return String.valueOf(input);
}

Green! Next step: refactoring. I don’t like the duplication of the return. We see “FizzBuzz” and then “Fizz” and “Buzz”. I have an idea that involves String concatenation on an output String. Let’s shortly check that and run the tests to see if I can take this big step:

private String fizzBuzz(int input) {
String output = "";
if (input % 3 == 0) {
output = output.concat("Fizz");
}
if (input % 5 == 0) {
output = output.concat("Buzz");
}
if (!output.equals("")) {
return output;
}
return String.valueOf(input);
}

Luckily it’s green. But the last if condition bothers me. I don’t want to have this dependency on an intermediate result (empty String), I want it on the inputs. And I prefer the concat with the plus sign:

private String fizzBuzz(int input) {
String output = "";
if (input % 3 == 0) {
output += "Fizz";
}
if (input % 5 == 0) {
output += "Buzz";
}
if (input % 3 != 0 && input % 5 != 0) {
output = String.valueOf(input);
}
return output;
}

Conclusion and Remarks!

Yes, I ignored the “numbers from 1 to 100” requirement. It can be an exercise for you ;) It might not exactly be the original FizzBuzz, but the base is there with the code above. Could this be a first step (towards 1 to 100), checking 1 to 6?

assertEquals("1, 2, Fizz, 4, Buzz, Fizz", fizzBuzz(6));

Furthermore, there are more elegant FizzBuzz implementations available than the one in this post.

If I would do this exercise 5 times. It would probably look a bit different each time. When do I move forward with teeny-tiny steps? Do I directly need to refactor each duplication on first sight? Do I need all the tests above? Why didn’t I test with input 4?
TDD is a set of techniques. How we apply them, is to a large part up to us. This will give us quick feedback, when we move too fast or in the wrong direction:

And this one is the return to safety:

Finally, don’t forget to look out for refactoring opportunities (spot the duplication!). And at the same time you shouldn’t hesitate to also revert if you don’t like the refactoring. You only took a little step to learn something about your code.

--

--