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

Do you need to strengthen the security of the mobile apps you build? Discover more than 50 secure mobile development coding practices to make your apps more secure.

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


Check out tips for blazing the way from agile to DevSecOps with security built into your mobile app toolchain.

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 }}