Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

TDD - Test Driven Development - Java JUnit FizzBuzz

DZone's Guide to

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.

· DevOps Zone ·
Free Resource

DevOps involves integrating development, testing, deployment and release cycles into a collaborative process. Learn more about the 4 steps to an effective DevSecOps infrastructure.

TDD 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


Read the 4-part DevOps testing eBook to learn how to detect problems earlier in your DevOps testing processes.

Topics:
java ,tdd ,junit ,fizzbuzz ,devops ,software testing

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}