TDD - Test Driven Development - Java JUnit FizzBuzz
In this article, we give a common programming interview question the TDD treatment, but from a tester's angle.
Join the DZone community and get the full member experience.
Join For FreeTDD Exercise - FizzBuzz
As part of a Sunday Morning practice session, I used FizzBuzz as my coding exercise.
I've heard that this is used in programming interviews and I so I thought I'd try it.
FizzBuzz rules are documented here.
The video I created of the TDD session is at the bottom of this post.
First I:
- Created a test class.
- Copied in the rules as a comment.
- Formatted the rules to make it easy to understand.
- Added some examples so that I could understand.
My First Test
The first Test I wrote was:
@Test
public void fizzBuzzConvertorLeavesNormalNumbersAlone(){
FizzBuzzConverter fizzBuzz = new FizzBuzzConverter();
Assert.assertEquals("1", fizzBuzz.convert(1));
}
This forced me to create the FizzBuzzConverter
class and convert
method.
I added a second assertion to this test:
Assert.assertEquals("2", fizzBuzz.convert(2));
This forced me to actually implement the default code in convert:
return String.valueOf(toConvertToFizzBuzz);
Thoughts on My First Test
Some people don't like multiple assertions in a Test.
Sometimes I do, sometimes I don't.
Here, I didn't mind:
- The test name allowed me to have multiple assertions.
- I thought multiple test methods would make it harder to Grok.
My Second Test
The second test was:
@Test
public void fizzBuzzConvertorMultiplesOfThree(){
FizzBuzzConverter fizzBuzz = new FizzBuzzConverter();
Assert.assertEquals("Fizz", fizzBuzz.convert(3));
}
This forced me to implement the "3" division rule:
if(toConvertToFizzBuzz%3==0){
return "Fizz";
}
I imagine that if you don't know the modulus operator then FizzBuzz can be quite hard.
I learned modulus back in the day of 8-bit programming and have been using it for various boundary, clipping, and scrolling routines ever since.
My Third Test
The third test was:
@Test
public void fizzBuzzConvertorMultiplesOfFive(){
FizzBuzzConverter fizzBuzz = new FizzBuzzConverter();
Assert.assertEquals("Buzz", fizzBuzz.convert(5));
}
Much the same as the condition for number 3:
if(toConvertToFizzBuzz%5==0){
return "Buzz";
}
At this point my convert
method looks as follows:
public String convert(int toConvertToFizzBuzz) {
if(toConvertToFizzBuzz%5==0){
return "Buzz";
}
if(toConvertToFizzBuzz%3==0){
return "Fizz";
}
return String.valueOf(toConvertToFizzBuzz);
}
Thoughts on Test 3
I have seen people create very complicated code for FizzBuzz.
I'm keeping it simple on the basis that. If I can get it working, then I can refactor it for efficiency or 'looking like a good programmer' later.
Test 4
My Fourth Test was much the same.
@Test
public void multiplesOfBothThreeAndFive(){
FizzBuzzConverter fizzBuzz = new FizzBuzzConverter();
Assert.assertEquals("FizzBuzz", fizzBuzz.convert(15));
}
At this point though, when I looked at the convert method I started to think:
- Should I add a flag to check for fizz and buzz?
- Should I have a set of nested ifs?
- Perhaps I can use a tertiary operator for some "magic."
Instead, I decided to keep it simple:
if(toConvertToFizzBuzz%15==0){
return "FizzBuzz";
}
Thoughts on Test 4
I suspect that this is the point at which people "fail" to implement FizzBuzz, because the code in the method becomes over complicated.
My @Test
methods do not warrant any complicated code:
public String convert(int toConvertToFizzBuzz) {
if(toConvertToFizzBuzz%15==0){
return "FizzBuzz";
}
if(toConvertToFizzBuzz%5==0){
return "Buzz";
}
if(toConvertToFizzBuzz%3==0){
return "Fizz";
}
return String.valueOf(toConvertToFizzBuzz);
}
There is a priority to the conditions where:
- 15 is higher priority because it is a combination of 3 and 5.
- 3 and 5 are equal priority and so it doesn't matter which order they are in.
- String conversion is the default so is lower priority.
In olden days we were taught to have a single return value per method. If I had written the code this way then it would be more complicated. Instead I
return
as soon as I've matched a condition.
The conditions are really as a set of "guards" to prevent fall through to the default operation.
Done
At this point, I'm "done."
Or at least I have an algorithm that will support the conversion of integers in the range 1 to 100 into Fizz, Buzz, Number or FizzBuzz
All I have to do is wrap it into something that will print out the values.
@Test
public void outputTheHundredFizzBuzzes(){
FizzBuzzConverter fizzBuzz = new FizzBuzzConverter();
for(int i=1; i<=100; i++){
System.out.println(fizzBuzz.convert(i));
}
}
I created it as an @Test
for expediency and I can execute it from the IDE.
And Then the Tester Kicks in
- I have used TDD to design the algorithm.
- I have not "tested" the output routine, I have executed it and seen the output from 1-100, but I don't really have an Oracle to compare that to
- I haven't asserted on my acceptance criteria but I have seen the values match my output from running
outputTheHundredFizzBuzzes
If this was a programming interview I might have to convert the
outputTheHundredFizzBuzzes
into a
main
method and run it, but the basic implementation of the requirements have been met.
As a tester I'm not sure I have convinced myself it "works," but it "works."
You can find all the code for this in the repo.
Video
Published at DZone with permission of Alan Richardson, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments