FizzBuzz
Fizz buzz (also written as FizzBuzz) was originally a word and number game used to teach children about division. In this game children sit in a circle and take turns counting from 1. However, if a number is divisible by 3, they say “Fizz,” if it is divisible by 5, they say “Buzz,” and if it divisible by both, they say “FizzBuzz.” More recently, it has found its way into the world of programming thanks to these blogs here and here. These blogs claim that many entry-level programmers, including those with a degree in computer science, cannot write a simple program that outputs the results of FizzBuzz. My task was to time myself while writing a program in Java, using Eclipse, that would output the results of FizzBuzz for the numbers 1 to 100. Beyond this, the implementation details were left up to me. However, I was also required to implement a test of the program to verify that the output was correct.
Implementation
The specific requirements of the task helped mold the way I approached this problem. First of all, in order to make the program easily testable, I created a method called getVal()
which would return the correct output for a given number, rather than including the logic in the main()
method. Secondly, because the requirements specified that I should only print the numbers from 1 to 100, I decided that trying to calculate anything outside of that range would throw an exception. The full text of the getVal()
method can be seen below.
public static String getVal(int n) throws IllegalArgumentException
{
if (n < 1 || n > 100) {
throw new IllegalArgumentException("n must be between 1 and 100, inclusive");
}
if (n % 15 == 0) {
return "FizzBuzz";
} else if (n % 3 == 0) {
return "Fizz";
} else if (n % 5 == 0) {
return "Buzz";
} else {
return String.valueOf(n);
}
}
Next, in order to print the results I created a simple main()
method which can be seen below.
public static void main(String[] args)
{
for (int i = 1; i <= 100; i++) {
System.out.println(FizzBuzz.getVal(i));
}
}
In total, it took about 5 minutes to complete the full program, which is shown below.
package edu.hawaii.ttaomae;
/**
* Prints the numbers 1 to 100 (inclusive) with one number per line.
* Number divisible by 3 are replaced with "Fizz", numbers divisible
* by 5 are replaced with "Buzz" and numbers divisible by both are
* replaced with "FizzBuzz".
*
* @author Todd Taomae
*/
public class FizzBuzz
{
/**
* Returns "Fizz", "Buzz", "FizzBuzz", or the String representation
* of n depending on
* @param n number to compute the value of
* @return "Fizz" if n is divisible by 3; "Buzz" if n is divisible
* by 5; "FizzBuzz" if n is divisible by 5 and 3; the
* String representation of the number otherwise.
* @throws IllegalArgumentException If n is below 1 or above 100
*/
public static String getVal(int n) throws IllegalArgumentException
{
if (n < 1 || n > 100) {
throw new IllegalArgumentException("n must be between 1 and 100, inclusive");
}
// if it is evenly divisible by 3 and 5, it is evenly divisible by 15
if (n % 15 == 0) {
return "FizzBuzz";
} else if (n % 3 == 0) {
return "Fizz";
} else if (n % 5 == 0) {
return "Buzz";
} else {
return String.valueOf(n);
}
}
public static void main(String[] args)
{
for (int i = 1; i <= 100; i++) {
System.out.println(FizzBuzz.getVal(i));
}
}
}
Testing
Upon initial inspection of the output, the program seemed correct. However, in order to test it more thoroughly, I used JUnit, which is a unit testing framework that is integrated into Eclipse. My experience with JUnit is very limited, so I started with simple assertions. I used separate methods to test the different cases. Specifically, I tested the following:
- Fizz (multiples of 3): 3, 33
- Buzz (multiples of 5): 5, 55
- FizzBuzz (multiples of 3 and 5): 15, 90
- non-FizzBuzz (not multiples of 3 or 5): 11, 77
- upper-bound: 100
- lower-bound: 1
This portion took about 5 minutes. After verifying that all these conditions were correct, I needed to verify that the program properly throws an exception when using a number that is outside the accepted boundaries. This was beyond the scope of my very limited knowledge of JUnit, so I resorted to Google. After a few minutes of searching, I found out how to test for exceptions. I added two more methods to test the following:
- above upper-bound: 101
- below lower-bound: 0
This portion took an additional 7 minutes, bringing my total time spent on this program to around 17 minutes.
The full text of the test program is shown below.
package edu.hawaii.ttaomae;
import static org.junit.Assert.*;
import org.junit.Test;
/**
* FizzBuzz test program.
*
* @author Todd Taomae
*/
public class FizzBuzzTest
{
@Test
public void testFizz()
{
assertEquals("Fizz", FizzBuzz.getVal(3));
assertEquals("Fizz", FizzBuzz.getVal(33));
}
@Test
public void testBuzz()
{
assertEquals("Buzz", FizzBuzz.getVal(5));
assertEquals("Buzz", FizzBuzz.getVal(55));
}
@Test
public void testFizzBuzz()
{
assertEquals("FizzBuzz", FizzBuzz.getVal(15));
assertEquals("FizzBuzz", FizzBuzz.getVal(90));
}
@Test
public void testNonFizzBuzz()
{
assertEquals("11", FizzBuzz.getVal(11));
assertEquals("77", FizzBuzz.getVal(77));
}
@Test
public void testUpperBound()
{
assertEquals("Buzz", FizzBuzz.getVal(100));
}
@Test
public void testLowerBound()
{
assertEquals("1", FizzBuzz.getVal(1));
}
@Test(expected=IllegalArgumentException.class)
public void testBelowLowerBound()
{
FizzBuzz.getVal(0);
}
@Test(expected=IllegalArgumentException.class)
public void testAboveUpperBound()
{
FizzBuzz.getVal(101);
}
}
Reflection
For any programmer worth their salt, it would be trivial to write an implementation of FizzBuzz, with paper and pencil, in a matter of minutes. In fact, that is something that I’ve done. But if it’s such a trivial program that should only take a few minutes, why did this implementation take me nearly 20 minutes? This exercise clearly demonstrates that good software engineering is not something that you can rush through. Writing good code involves a lot more than just producing the correct output. You must consider implementation details that may not be specified, you need to properly comment your code, and perhaps most importantly, even for something as simple as FizzBuzz, you need to properly test your program to ensure that you are actually getting the correct results.