Fizz Buzz Test Driven Development
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
4
down vote
favorite
Task:
Create the Fizz Buzz game using Test Driven Developoment. Print the correct word for range 1-100.
The implementation:
public class Main
static final String FIZZ = "Fizz";
static final String BUZZ = "Buzz";
static final String FIZZ_BUZZ = "Fizz Buzz";
public static void main(String args)
IntStream.range(1, 101).forEach((x) -> System.out.println(getWordForNumber(x)));
public static String getWordForNumber(int x)
if (isDivisibleWithoutRemainder(x, 15))
return FIZZ_BUZZ;
else if(isDivisibleWithoutRemainder(x, 3))
return FIZZ;
else if(isDivisibleWithoutRemainder(x, 5))
return BUZZ;
return Integer.toString(x);
private static boolean isDivisibleWithoutRemainder(int dividend, int divisor)
return (dividend%divisor == 0);
The JUnit Test:
final class Number
private final int n;
Number (int number)
n = number;
final boolean isMatchedToWord(final String word)
return Main.getWordForNumber(n).equals(word);
class MainTest
@Test
public void numbersAreMatchedToWords_Works()
assertTrue(new Number(1).isMatchedToWord("1"));
assertTrue(new Number(2).isMatchedToWord("2"));
assertTrue(new Number(3).isMatchedToWord("Fizz"));
assertTrue(new Number(4).isMatchedToWord("4"));
assertTrue(new Number(5).isMatchedToWord("Buzz"));
assertTrue(new Number(6).isMatchedToWord("Fizz"));
assertTrue(new Number(10).isMatchedToWord("Buzz"));
assertTrue(new Number(15).isMatchedToWord("Fizz Buzz"));
assertTrue(new Number(30).isMatchedToWord("Fizz Buzz"));
java unit-testing fizzbuzz junit
add a comment |Â
up vote
4
down vote
favorite
Task:
Create the Fizz Buzz game using Test Driven Developoment. Print the correct word for range 1-100.
The implementation:
public class Main
static final String FIZZ = "Fizz";
static final String BUZZ = "Buzz";
static final String FIZZ_BUZZ = "Fizz Buzz";
public static void main(String args)
IntStream.range(1, 101).forEach((x) -> System.out.println(getWordForNumber(x)));
public static String getWordForNumber(int x)
if (isDivisibleWithoutRemainder(x, 15))
return FIZZ_BUZZ;
else if(isDivisibleWithoutRemainder(x, 3))
return FIZZ;
else if(isDivisibleWithoutRemainder(x, 5))
return BUZZ;
return Integer.toString(x);
private static boolean isDivisibleWithoutRemainder(int dividend, int divisor)
return (dividend%divisor == 0);
The JUnit Test:
final class Number
private final int n;
Number (int number)
n = number;
final boolean isMatchedToWord(final String word)
return Main.getWordForNumber(n).equals(word);
class MainTest
@Test
public void numbersAreMatchedToWords_Works()
assertTrue(new Number(1).isMatchedToWord("1"));
assertTrue(new Number(2).isMatchedToWord("2"));
assertTrue(new Number(3).isMatchedToWord("Fizz"));
assertTrue(new Number(4).isMatchedToWord("4"));
assertTrue(new Number(5).isMatchedToWord("Buzz"));
assertTrue(new Number(6).isMatchedToWord("Fizz"));
assertTrue(new Number(10).isMatchedToWord("Buzz"));
assertTrue(new Number(15).isMatchedToWord("Fizz Buzz"));
assertTrue(new Number(30).isMatchedToWord("Fizz Buzz"));
java unit-testing fizzbuzz junit
add a comment |Â
up vote
4
down vote
favorite
up vote
4
down vote
favorite
Task:
Create the Fizz Buzz game using Test Driven Developoment. Print the correct word for range 1-100.
The implementation:
public class Main
static final String FIZZ = "Fizz";
static final String BUZZ = "Buzz";
static final String FIZZ_BUZZ = "Fizz Buzz";
public static void main(String args)
IntStream.range(1, 101).forEach((x) -> System.out.println(getWordForNumber(x)));
public static String getWordForNumber(int x)
if (isDivisibleWithoutRemainder(x, 15))
return FIZZ_BUZZ;
else if(isDivisibleWithoutRemainder(x, 3))
return FIZZ;
else if(isDivisibleWithoutRemainder(x, 5))
return BUZZ;
return Integer.toString(x);
private static boolean isDivisibleWithoutRemainder(int dividend, int divisor)
return (dividend%divisor == 0);
The JUnit Test:
final class Number
private final int n;
Number (int number)
n = number;
final boolean isMatchedToWord(final String word)
return Main.getWordForNumber(n).equals(word);
class MainTest
@Test
public void numbersAreMatchedToWords_Works()
assertTrue(new Number(1).isMatchedToWord("1"));
assertTrue(new Number(2).isMatchedToWord("2"));
assertTrue(new Number(3).isMatchedToWord("Fizz"));
assertTrue(new Number(4).isMatchedToWord("4"));
assertTrue(new Number(5).isMatchedToWord("Buzz"));
assertTrue(new Number(6).isMatchedToWord("Fizz"));
assertTrue(new Number(10).isMatchedToWord("Buzz"));
assertTrue(new Number(15).isMatchedToWord("Fizz Buzz"));
assertTrue(new Number(30).isMatchedToWord("Fizz Buzz"));
java unit-testing fizzbuzz junit
Task:
Create the Fizz Buzz game using Test Driven Developoment. Print the correct word for range 1-100.
The implementation:
public class Main
static final String FIZZ = "Fizz";
static final String BUZZ = "Buzz";
static final String FIZZ_BUZZ = "Fizz Buzz";
public static void main(String args)
IntStream.range(1, 101).forEach((x) -> System.out.println(getWordForNumber(x)));
public static String getWordForNumber(int x)
if (isDivisibleWithoutRemainder(x, 15))
return FIZZ_BUZZ;
else if(isDivisibleWithoutRemainder(x, 3))
return FIZZ;
else if(isDivisibleWithoutRemainder(x, 5))
return BUZZ;
return Integer.toString(x);
private static boolean isDivisibleWithoutRemainder(int dividend, int divisor)
return (dividend%divisor == 0);
The JUnit Test:
final class Number
private final int n;
Number (int number)
n = number;
final boolean isMatchedToWord(final String word)
return Main.getWordForNumber(n).equals(word);
class MainTest
@Test
public void numbersAreMatchedToWords_Works()
assertTrue(new Number(1).isMatchedToWord("1"));
assertTrue(new Number(2).isMatchedToWord("2"));
assertTrue(new Number(3).isMatchedToWord("Fizz"));
assertTrue(new Number(4).isMatchedToWord("4"));
assertTrue(new Number(5).isMatchedToWord("Buzz"));
assertTrue(new Number(6).isMatchedToWord("Fizz"));
assertTrue(new Number(10).isMatchedToWord("Buzz"));
assertTrue(new Number(15).isMatchedToWord("Fizz Buzz"));
assertTrue(new Number(30).isMatchedToWord("Fizz Buzz"));
java unit-testing fizzbuzz junit
asked May 11 at 10:27
Matthias Herrmann
1624
1624
add a comment |Â
add a comment |Â
3 Answers
3
active
oldest
votes
up vote
4
down vote
accepted
- Prefer
IntStream.rangeClosed(1, 100)
instead ofIntStream.range(1, 101)
- Be consistent in spacing,
if (isDivisibleWithoutRemainder(x, 3))
is better thanif(isDivisibleWithoutRemainder(x, 3))
(note the space afterif
) return (dividend%divisor == 0);
does not need the parenthesis, I would also recommend to give it a bit more space.return dividend % divisor == 0;
- Use
assertEquals
in your test instead ofassertTrue
to show a better error message if the test fails - You could write your own helping method to test a number instead of having the
Number
class, such astestNumber(4, "4");
which basically doesassertEquals(word, Main.getWordForNumber(n));
- Don't test all cases in the same method. If one goes wrong you need to fix it before you can see the results of the others below it. Preferably use a JUnit parameterized test
IntStream.rangeClosed
is definitive better. I didn't know about the parameterized tests; they seem very useful - ty
â Matthias Herrmann
May 11 at 10:58
add a comment |Â
up vote
5
down vote
Test driven development
In test driven development you let the code and the tests evolve by repeating the following steps:
- Add a new test case that fails, the simplest possible
- Fix the implementation the simplest possible way so that all test cases pass
- Optionally refactor the existing code, while keeping all tests passing
- Repeat from step 1
There are variations to these steps, but one thing is certain: in the end you will have many test cases. The posted code has one, which means it wasn't really developed using TDD.
Keep it simple
It's good to keep everything as simple as possible. In the test class, do you really need a Number
class to wrap an number, so that you create an instance and then call a method on that instance? A simple method would have been enough, that takes an integer as parameter and returns a string.
What you see above is the result of me applying test driven development. I wrote always a unit test that has failed before writing enough and not a single line more so that the test succeeded. Each assert statement is one unit test that initially failed (so I got 9x iterations). To the second part: Yes you are right theNumber
class isn't the best solution. I wanted that someone who is reading the test can simply readnumber x is being matched to word y
. In C++ I could just overload theoperator()
but in Java that doesn't work, so I had to create an instance....
â Matthias Herrmann
May 11 at 11:54
I didn't write 9 test methods because of the DRY principle. But as @SimonForsberg pointed out parameterized tests are a possible solution for this issue.
â Matthias Herrmann
May 11 at 12:01
3
@MatthiasHerrmann Fair enough about the iterations, but there really has to be distinct method (= test case), not just a new assertion in an existing one. The unit of growth is the test case. It's best when the new test method has name that describes its purpose. It takes some practice to come up with good names.
â janos
May 11 at 12:25
2
@MatthiasHerrmann as for fluent assertions, I recommend using theassertj
library. You will be able to write likeassertThat(getWordForNumber(3)).isEqualTo("Fizz");
, which I think comes very close to what you wanted to achieve. Even without that,assertEquals(getWordForNumber(3), "Fizz")
would have been better than the current solution.
â janos
May 11 at 12:27
1
@janos Don't forget that expected comes before actual, so that'd beassertEquals("Fizz", getWordForNumber(3))
â Simon Forsbergâ¦
May 11 at 16:29
add a comment |Â
up vote
3
down vote
FIZZ = "Fizz"
really? I'm amazed no one has mentioned that naming variables after their values will earn you a special place in the after life. Don't couple names to values.
Most of what's been said here I agree with but another issue that's been ignored is the code for 15.
Try adding a requirement to print "Bazz" on multiples of 7 and I think you'll see why I'm taking issue with branching off of 15.
If you don't, here's a well thought out blog post on Fizz Buzz that delves into the 15 issue called The Wrong FizzBuzz. It almost shows you a better way to solve this problem. Unfortunately it makes a fatal mistake and changes the requirements to make it's prefered solution easier.
The problem with hard coding 15 is it's an invitation for new requirements to cause a combinatorial explosion of code. There is a simple way around it. Just treat your string like the collection of letters it is and add to it.
public static String getWordForNumber(int x)
String result = "";
if ( isDivisibleBy(x, 3) )
result += "Fizz";
if ( isDivisibleBy(x, 5) )
result += "Buzz";
if ( result.equals("") )
result = Integer.toString(x);
return result;
Now yes, just like the blog this doesn't quite work. Darn spaces are messing it up. But it only needs three little changes. Easy fix.
public static String getWordForNumber(int x)
String result = "";
if ( isDivisibleBy(x, 3) )
result += " Fizz";
if ( isDivisibleBy(x, 5) )
result += " Buzz";
if ( result.equals("") )
result = Integer.toString(x);
return result.trim();
Now it passes all the tests and the only numbers that will ever need to be mentioned are prime.
There's two different (reasonable) possible requirements that can happen: A) Add "Bazz" on multiples of 7. B) Print "Quack" for multiples of 15 instead of "FizzBuzz". It's hard to build and be prepared for both of those scenarios.
â Simon Forsbergâ¦
May 14 at 15:18
@SimonForsberg I don't see how that forces an explosion of code. Just start withif ( isDivisibleBy(x, 15) ) return "Quack";
and the rest still works. The pattern is to treat prime numbers and compound numbers differently.
â candied_orange
May 14 at 18:16
add a comment |Â
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
4
down vote
accepted
- Prefer
IntStream.rangeClosed(1, 100)
instead ofIntStream.range(1, 101)
- Be consistent in spacing,
if (isDivisibleWithoutRemainder(x, 3))
is better thanif(isDivisibleWithoutRemainder(x, 3))
(note the space afterif
) return (dividend%divisor == 0);
does not need the parenthesis, I would also recommend to give it a bit more space.return dividend % divisor == 0;
- Use
assertEquals
in your test instead ofassertTrue
to show a better error message if the test fails - You could write your own helping method to test a number instead of having the
Number
class, such astestNumber(4, "4");
which basically doesassertEquals(word, Main.getWordForNumber(n));
- Don't test all cases in the same method. If one goes wrong you need to fix it before you can see the results of the others below it. Preferably use a JUnit parameterized test
IntStream.rangeClosed
is definitive better. I didn't know about the parameterized tests; they seem very useful - ty
â Matthias Herrmann
May 11 at 10:58
add a comment |Â
up vote
4
down vote
accepted
- Prefer
IntStream.rangeClosed(1, 100)
instead ofIntStream.range(1, 101)
- Be consistent in spacing,
if (isDivisibleWithoutRemainder(x, 3))
is better thanif(isDivisibleWithoutRemainder(x, 3))
(note the space afterif
) return (dividend%divisor == 0);
does not need the parenthesis, I would also recommend to give it a bit more space.return dividend % divisor == 0;
- Use
assertEquals
in your test instead ofassertTrue
to show a better error message if the test fails - You could write your own helping method to test a number instead of having the
Number
class, such astestNumber(4, "4");
which basically doesassertEquals(word, Main.getWordForNumber(n));
- Don't test all cases in the same method. If one goes wrong you need to fix it before you can see the results of the others below it. Preferably use a JUnit parameterized test
IntStream.rangeClosed
is definitive better. I didn't know about the parameterized tests; they seem very useful - ty
â Matthias Herrmann
May 11 at 10:58
add a comment |Â
up vote
4
down vote
accepted
up vote
4
down vote
accepted
- Prefer
IntStream.rangeClosed(1, 100)
instead ofIntStream.range(1, 101)
- Be consistent in spacing,
if (isDivisibleWithoutRemainder(x, 3))
is better thanif(isDivisibleWithoutRemainder(x, 3))
(note the space afterif
) return (dividend%divisor == 0);
does not need the parenthesis, I would also recommend to give it a bit more space.return dividend % divisor == 0;
- Use
assertEquals
in your test instead ofassertTrue
to show a better error message if the test fails - You could write your own helping method to test a number instead of having the
Number
class, such astestNumber(4, "4");
which basically doesassertEquals(word, Main.getWordForNumber(n));
- Don't test all cases in the same method. If one goes wrong you need to fix it before you can see the results of the others below it. Preferably use a JUnit parameterized test
- Prefer
IntStream.rangeClosed(1, 100)
instead ofIntStream.range(1, 101)
- Be consistent in spacing,
if (isDivisibleWithoutRemainder(x, 3))
is better thanif(isDivisibleWithoutRemainder(x, 3))
(note the space afterif
) return (dividend%divisor == 0);
does not need the parenthesis, I would also recommend to give it a bit more space.return dividend % divisor == 0;
- Use
assertEquals
in your test instead ofassertTrue
to show a better error message if the test fails - You could write your own helping method to test a number instead of having the
Number
class, such astestNumber(4, "4");
which basically doesassertEquals(word, Main.getWordForNumber(n));
- Don't test all cases in the same method. If one goes wrong you need to fix it before you can see the results of the others below it. Preferably use a JUnit parameterized test
edited May 14 at 15:13
answered May 11 at 10:48
Simon Forsbergâ¦
48.1k7124283
48.1k7124283
IntStream.rangeClosed
is definitive better. I didn't know about the parameterized tests; they seem very useful - ty
â Matthias Herrmann
May 11 at 10:58
add a comment |Â
IntStream.rangeClosed
is definitive better. I didn't know about the parameterized tests; they seem very useful - ty
â Matthias Herrmann
May 11 at 10:58
IntStream.rangeClosed
is definitive better. I didn't know about the parameterized tests; they seem very useful - tyâ Matthias Herrmann
May 11 at 10:58
IntStream.rangeClosed
is definitive better. I didn't know about the parameterized tests; they seem very useful - tyâ Matthias Herrmann
May 11 at 10:58
add a comment |Â
up vote
5
down vote
Test driven development
In test driven development you let the code and the tests evolve by repeating the following steps:
- Add a new test case that fails, the simplest possible
- Fix the implementation the simplest possible way so that all test cases pass
- Optionally refactor the existing code, while keeping all tests passing
- Repeat from step 1
There are variations to these steps, but one thing is certain: in the end you will have many test cases. The posted code has one, which means it wasn't really developed using TDD.
Keep it simple
It's good to keep everything as simple as possible. In the test class, do you really need a Number
class to wrap an number, so that you create an instance and then call a method on that instance? A simple method would have been enough, that takes an integer as parameter and returns a string.
What you see above is the result of me applying test driven development. I wrote always a unit test that has failed before writing enough and not a single line more so that the test succeeded. Each assert statement is one unit test that initially failed (so I got 9x iterations). To the second part: Yes you are right theNumber
class isn't the best solution. I wanted that someone who is reading the test can simply readnumber x is being matched to word y
. In C++ I could just overload theoperator()
but in Java that doesn't work, so I had to create an instance....
â Matthias Herrmann
May 11 at 11:54
I didn't write 9 test methods because of the DRY principle. But as @SimonForsberg pointed out parameterized tests are a possible solution for this issue.
â Matthias Herrmann
May 11 at 12:01
3
@MatthiasHerrmann Fair enough about the iterations, but there really has to be distinct method (= test case), not just a new assertion in an existing one. The unit of growth is the test case. It's best when the new test method has name that describes its purpose. It takes some practice to come up with good names.
â janos
May 11 at 12:25
2
@MatthiasHerrmann as for fluent assertions, I recommend using theassertj
library. You will be able to write likeassertThat(getWordForNumber(3)).isEqualTo("Fizz");
, which I think comes very close to what you wanted to achieve. Even without that,assertEquals(getWordForNumber(3), "Fizz")
would have been better than the current solution.
â janos
May 11 at 12:27
1
@janos Don't forget that expected comes before actual, so that'd beassertEquals("Fizz", getWordForNumber(3))
â Simon Forsbergâ¦
May 11 at 16:29
add a comment |Â
up vote
5
down vote
Test driven development
In test driven development you let the code and the tests evolve by repeating the following steps:
- Add a new test case that fails, the simplest possible
- Fix the implementation the simplest possible way so that all test cases pass
- Optionally refactor the existing code, while keeping all tests passing
- Repeat from step 1
There are variations to these steps, but one thing is certain: in the end you will have many test cases. The posted code has one, which means it wasn't really developed using TDD.
Keep it simple
It's good to keep everything as simple as possible. In the test class, do you really need a Number
class to wrap an number, so that you create an instance and then call a method on that instance? A simple method would have been enough, that takes an integer as parameter and returns a string.
What you see above is the result of me applying test driven development. I wrote always a unit test that has failed before writing enough and not a single line more so that the test succeeded. Each assert statement is one unit test that initially failed (so I got 9x iterations). To the second part: Yes you are right theNumber
class isn't the best solution. I wanted that someone who is reading the test can simply readnumber x is being matched to word y
. In C++ I could just overload theoperator()
but in Java that doesn't work, so I had to create an instance....
â Matthias Herrmann
May 11 at 11:54
I didn't write 9 test methods because of the DRY principle. But as @SimonForsberg pointed out parameterized tests are a possible solution for this issue.
â Matthias Herrmann
May 11 at 12:01
3
@MatthiasHerrmann Fair enough about the iterations, but there really has to be distinct method (= test case), not just a new assertion in an existing one. The unit of growth is the test case. It's best when the new test method has name that describes its purpose. It takes some practice to come up with good names.
â janos
May 11 at 12:25
2
@MatthiasHerrmann as for fluent assertions, I recommend using theassertj
library. You will be able to write likeassertThat(getWordForNumber(3)).isEqualTo("Fizz");
, which I think comes very close to what you wanted to achieve. Even without that,assertEquals(getWordForNumber(3), "Fizz")
would have been better than the current solution.
â janos
May 11 at 12:27
1
@janos Don't forget that expected comes before actual, so that'd beassertEquals("Fizz", getWordForNumber(3))
â Simon Forsbergâ¦
May 11 at 16:29
add a comment |Â
up vote
5
down vote
up vote
5
down vote
Test driven development
In test driven development you let the code and the tests evolve by repeating the following steps:
- Add a new test case that fails, the simplest possible
- Fix the implementation the simplest possible way so that all test cases pass
- Optionally refactor the existing code, while keeping all tests passing
- Repeat from step 1
There are variations to these steps, but one thing is certain: in the end you will have many test cases. The posted code has one, which means it wasn't really developed using TDD.
Keep it simple
It's good to keep everything as simple as possible. In the test class, do you really need a Number
class to wrap an number, so that you create an instance and then call a method on that instance? A simple method would have been enough, that takes an integer as parameter and returns a string.
Test driven development
In test driven development you let the code and the tests evolve by repeating the following steps:
- Add a new test case that fails, the simplest possible
- Fix the implementation the simplest possible way so that all test cases pass
- Optionally refactor the existing code, while keeping all tests passing
- Repeat from step 1
There are variations to these steps, but one thing is certain: in the end you will have many test cases. The posted code has one, which means it wasn't really developed using TDD.
Keep it simple
It's good to keep everything as simple as possible. In the test class, do you really need a Number
class to wrap an number, so that you create an instance and then call a method on that instance? A simple method would have been enough, that takes an integer as parameter and returns a string.
answered May 11 at 11:45
janos
95.4k12119342
95.4k12119342
What you see above is the result of me applying test driven development. I wrote always a unit test that has failed before writing enough and not a single line more so that the test succeeded. Each assert statement is one unit test that initially failed (so I got 9x iterations). To the second part: Yes you are right theNumber
class isn't the best solution. I wanted that someone who is reading the test can simply readnumber x is being matched to word y
. In C++ I could just overload theoperator()
but in Java that doesn't work, so I had to create an instance....
â Matthias Herrmann
May 11 at 11:54
I didn't write 9 test methods because of the DRY principle. But as @SimonForsberg pointed out parameterized tests are a possible solution for this issue.
â Matthias Herrmann
May 11 at 12:01
3
@MatthiasHerrmann Fair enough about the iterations, but there really has to be distinct method (= test case), not just a new assertion in an existing one. The unit of growth is the test case. It's best when the new test method has name that describes its purpose. It takes some practice to come up with good names.
â janos
May 11 at 12:25
2
@MatthiasHerrmann as for fluent assertions, I recommend using theassertj
library. You will be able to write likeassertThat(getWordForNumber(3)).isEqualTo("Fizz");
, which I think comes very close to what you wanted to achieve. Even without that,assertEquals(getWordForNumber(3), "Fizz")
would have been better than the current solution.
â janos
May 11 at 12:27
1
@janos Don't forget that expected comes before actual, so that'd beassertEquals("Fizz", getWordForNumber(3))
â Simon Forsbergâ¦
May 11 at 16:29
add a comment |Â
What you see above is the result of me applying test driven development. I wrote always a unit test that has failed before writing enough and not a single line more so that the test succeeded. Each assert statement is one unit test that initially failed (so I got 9x iterations). To the second part: Yes you are right theNumber
class isn't the best solution. I wanted that someone who is reading the test can simply readnumber x is being matched to word y
. In C++ I could just overload theoperator()
but in Java that doesn't work, so I had to create an instance....
â Matthias Herrmann
May 11 at 11:54
I didn't write 9 test methods because of the DRY principle. But as @SimonForsberg pointed out parameterized tests are a possible solution for this issue.
â Matthias Herrmann
May 11 at 12:01
3
@MatthiasHerrmann Fair enough about the iterations, but there really has to be distinct method (= test case), not just a new assertion in an existing one. The unit of growth is the test case. It's best when the new test method has name that describes its purpose. It takes some practice to come up with good names.
â janos
May 11 at 12:25
2
@MatthiasHerrmann as for fluent assertions, I recommend using theassertj
library. You will be able to write likeassertThat(getWordForNumber(3)).isEqualTo("Fizz");
, which I think comes very close to what you wanted to achieve. Even without that,assertEquals(getWordForNumber(3), "Fizz")
would have been better than the current solution.
â janos
May 11 at 12:27
1
@janos Don't forget that expected comes before actual, so that'd beassertEquals("Fizz", getWordForNumber(3))
â Simon Forsbergâ¦
May 11 at 16:29
What you see above is the result of me applying test driven development. I wrote always a unit test that has failed before writing enough and not a single line more so that the test succeeded. Each assert statement is one unit test that initially failed (so I got 9x iterations). To the second part: Yes you are right the
Number
class isn't the best solution. I wanted that someone who is reading the test can simply read number x is being matched to word y
. In C++ I could just overload the operator()
but in Java that doesn't work, so I had to create an instance....â Matthias Herrmann
May 11 at 11:54
What you see above is the result of me applying test driven development. I wrote always a unit test that has failed before writing enough and not a single line more so that the test succeeded. Each assert statement is one unit test that initially failed (so I got 9x iterations). To the second part: Yes you are right the
Number
class isn't the best solution. I wanted that someone who is reading the test can simply read number x is being matched to word y
. In C++ I could just overload the operator()
but in Java that doesn't work, so I had to create an instance....â Matthias Herrmann
May 11 at 11:54
I didn't write 9 test methods because of the DRY principle. But as @SimonForsberg pointed out parameterized tests are a possible solution for this issue.
â Matthias Herrmann
May 11 at 12:01
I didn't write 9 test methods because of the DRY principle. But as @SimonForsberg pointed out parameterized tests are a possible solution for this issue.
â Matthias Herrmann
May 11 at 12:01
3
3
@MatthiasHerrmann Fair enough about the iterations, but there really has to be distinct method (= test case), not just a new assertion in an existing one. The unit of growth is the test case. It's best when the new test method has name that describes its purpose. It takes some practice to come up with good names.
â janos
May 11 at 12:25
@MatthiasHerrmann Fair enough about the iterations, but there really has to be distinct method (= test case), not just a new assertion in an existing one. The unit of growth is the test case. It's best when the new test method has name that describes its purpose. It takes some practice to come up with good names.
â janos
May 11 at 12:25
2
2
@MatthiasHerrmann as for fluent assertions, I recommend using the
assertj
library. You will be able to write like assertThat(getWordForNumber(3)).isEqualTo("Fizz");
, which I think comes very close to what you wanted to achieve. Even without that, assertEquals(getWordForNumber(3), "Fizz")
would have been better than the current solution.â janos
May 11 at 12:27
@MatthiasHerrmann as for fluent assertions, I recommend using the
assertj
library. You will be able to write like assertThat(getWordForNumber(3)).isEqualTo("Fizz");
, which I think comes very close to what you wanted to achieve. Even without that, assertEquals(getWordForNumber(3), "Fizz")
would have been better than the current solution.â janos
May 11 at 12:27
1
1
@janos Don't forget that expected comes before actual, so that'd be
assertEquals("Fizz", getWordForNumber(3))
â Simon Forsbergâ¦
May 11 at 16:29
@janos Don't forget that expected comes before actual, so that'd be
assertEquals("Fizz", getWordForNumber(3))
â Simon Forsbergâ¦
May 11 at 16:29
add a comment |Â
up vote
3
down vote
FIZZ = "Fizz"
really? I'm amazed no one has mentioned that naming variables after their values will earn you a special place in the after life. Don't couple names to values.
Most of what's been said here I agree with but another issue that's been ignored is the code for 15.
Try adding a requirement to print "Bazz" on multiples of 7 and I think you'll see why I'm taking issue with branching off of 15.
If you don't, here's a well thought out blog post on Fizz Buzz that delves into the 15 issue called The Wrong FizzBuzz. It almost shows you a better way to solve this problem. Unfortunately it makes a fatal mistake and changes the requirements to make it's prefered solution easier.
The problem with hard coding 15 is it's an invitation for new requirements to cause a combinatorial explosion of code. There is a simple way around it. Just treat your string like the collection of letters it is and add to it.
public static String getWordForNumber(int x)
String result = "";
if ( isDivisibleBy(x, 3) )
result += "Fizz";
if ( isDivisibleBy(x, 5) )
result += "Buzz";
if ( result.equals("") )
result = Integer.toString(x);
return result;
Now yes, just like the blog this doesn't quite work. Darn spaces are messing it up. But it only needs three little changes. Easy fix.
public static String getWordForNumber(int x)
String result = "";
if ( isDivisibleBy(x, 3) )
result += " Fizz";
if ( isDivisibleBy(x, 5) )
result += " Buzz";
if ( result.equals("") )
result = Integer.toString(x);
return result.trim();
Now it passes all the tests and the only numbers that will ever need to be mentioned are prime.
There's two different (reasonable) possible requirements that can happen: A) Add "Bazz" on multiples of 7. B) Print "Quack" for multiples of 15 instead of "FizzBuzz". It's hard to build and be prepared for both of those scenarios.
â Simon Forsbergâ¦
May 14 at 15:18
@SimonForsberg I don't see how that forces an explosion of code. Just start withif ( isDivisibleBy(x, 15) ) return "Quack";
and the rest still works. The pattern is to treat prime numbers and compound numbers differently.
â candied_orange
May 14 at 18:16
add a comment |Â
up vote
3
down vote
FIZZ = "Fizz"
really? I'm amazed no one has mentioned that naming variables after their values will earn you a special place in the after life. Don't couple names to values.
Most of what's been said here I agree with but another issue that's been ignored is the code for 15.
Try adding a requirement to print "Bazz" on multiples of 7 and I think you'll see why I'm taking issue with branching off of 15.
If you don't, here's a well thought out blog post on Fizz Buzz that delves into the 15 issue called The Wrong FizzBuzz. It almost shows you a better way to solve this problem. Unfortunately it makes a fatal mistake and changes the requirements to make it's prefered solution easier.
The problem with hard coding 15 is it's an invitation for new requirements to cause a combinatorial explosion of code. There is a simple way around it. Just treat your string like the collection of letters it is and add to it.
public static String getWordForNumber(int x)
String result = "";
if ( isDivisibleBy(x, 3) )
result += "Fizz";
if ( isDivisibleBy(x, 5) )
result += "Buzz";
if ( result.equals("") )
result = Integer.toString(x);
return result;
Now yes, just like the blog this doesn't quite work. Darn spaces are messing it up. But it only needs three little changes. Easy fix.
public static String getWordForNumber(int x)
String result = "";
if ( isDivisibleBy(x, 3) )
result += " Fizz";
if ( isDivisibleBy(x, 5) )
result += " Buzz";
if ( result.equals("") )
result = Integer.toString(x);
return result.trim();
Now it passes all the tests and the only numbers that will ever need to be mentioned are prime.
There's two different (reasonable) possible requirements that can happen: A) Add "Bazz" on multiples of 7. B) Print "Quack" for multiples of 15 instead of "FizzBuzz". It's hard to build and be prepared for both of those scenarios.
â Simon Forsbergâ¦
May 14 at 15:18
@SimonForsberg I don't see how that forces an explosion of code. Just start withif ( isDivisibleBy(x, 15) ) return "Quack";
and the rest still works. The pattern is to treat prime numbers and compound numbers differently.
â candied_orange
May 14 at 18:16
add a comment |Â
up vote
3
down vote
up vote
3
down vote
FIZZ = "Fizz"
really? I'm amazed no one has mentioned that naming variables after their values will earn you a special place in the after life. Don't couple names to values.
Most of what's been said here I agree with but another issue that's been ignored is the code for 15.
Try adding a requirement to print "Bazz" on multiples of 7 and I think you'll see why I'm taking issue with branching off of 15.
If you don't, here's a well thought out blog post on Fizz Buzz that delves into the 15 issue called The Wrong FizzBuzz. It almost shows you a better way to solve this problem. Unfortunately it makes a fatal mistake and changes the requirements to make it's prefered solution easier.
The problem with hard coding 15 is it's an invitation for new requirements to cause a combinatorial explosion of code. There is a simple way around it. Just treat your string like the collection of letters it is and add to it.
public static String getWordForNumber(int x)
String result = "";
if ( isDivisibleBy(x, 3) )
result += "Fizz";
if ( isDivisibleBy(x, 5) )
result += "Buzz";
if ( result.equals("") )
result = Integer.toString(x);
return result;
Now yes, just like the blog this doesn't quite work. Darn spaces are messing it up. But it only needs three little changes. Easy fix.
public static String getWordForNumber(int x)
String result = "";
if ( isDivisibleBy(x, 3) )
result += " Fizz";
if ( isDivisibleBy(x, 5) )
result += " Buzz";
if ( result.equals("") )
result = Integer.toString(x);
return result.trim();
Now it passes all the tests and the only numbers that will ever need to be mentioned are prime.
FIZZ = "Fizz"
really? I'm amazed no one has mentioned that naming variables after their values will earn you a special place in the after life. Don't couple names to values.
Most of what's been said here I agree with but another issue that's been ignored is the code for 15.
Try adding a requirement to print "Bazz" on multiples of 7 and I think you'll see why I'm taking issue with branching off of 15.
If you don't, here's a well thought out blog post on Fizz Buzz that delves into the 15 issue called The Wrong FizzBuzz. It almost shows you a better way to solve this problem. Unfortunately it makes a fatal mistake and changes the requirements to make it's prefered solution easier.
The problem with hard coding 15 is it's an invitation for new requirements to cause a combinatorial explosion of code. There is a simple way around it. Just treat your string like the collection of letters it is and add to it.
public static String getWordForNumber(int x)
String result = "";
if ( isDivisibleBy(x, 3) )
result += "Fizz";
if ( isDivisibleBy(x, 5) )
result += "Buzz";
if ( result.equals("") )
result = Integer.toString(x);
return result;
Now yes, just like the blog this doesn't quite work. Darn spaces are messing it up. But it only needs three little changes. Easy fix.
public static String getWordForNumber(int x)
String result = "";
if ( isDivisibleBy(x, 3) )
result += " Fizz";
if ( isDivisibleBy(x, 5) )
result += " Buzz";
if ( result.equals("") )
result = Integer.toString(x);
return result.trim();
Now it passes all the tests and the only numbers that will ever need to be mentioned are prime.
edited May 12 at 4:54
answered May 12 at 4:49
candied_orange
377217
377217
There's two different (reasonable) possible requirements that can happen: A) Add "Bazz" on multiples of 7. B) Print "Quack" for multiples of 15 instead of "FizzBuzz". It's hard to build and be prepared for both of those scenarios.
â Simon Forsbergâ¦
May 14 at 15:18
@SimonForsberg I don't see how that forces an explosion of code. Just start withif ( isDivisibleBy(x, 15) ) return "Quack";
and the rest still works. The pattern is to treat prime numbers and compound numbers differently.
â candied_orange
May 14 at 18:16
add a comment |Â
There's two different (reasonable) possible requirements that can happen: A) Add "Bazz" on multiples of 7. B) Print "Quack" for multiples of 15 instead of "FizzBuzz". It's hard to build and be prepared for both of those scenarios.
â Simon Forsbergâ¦
May 14 at 15:18
@SimonForsberg I don't see how that forces an explosion of code. Just start withif ( isDivisibleBy(x, 15) ) return "Quack";
and the rest still works. The pattern is to treat prime numbers and compound numbers differently.
â candied_orange
May 14 at 18:16
There's two different (reasonable) possible requirements that can happen: A) Add "Bazz" on multiples of 7. B) Print "Quack" for multiples of 15 instead of "FizzBuzz". It's hard to build and be prepared for both of those scenarios.
â Simon Forsbergâ¦
May 14 at 15:18
There's two different (reasonable) possible requirements that can happen: A) Add "Bazz" on multiples of 7. B) Print "Quack" for multiples of 15 instead of "FizzBuzz". It's hard to build and be prepared for both of those scenarios.
â Simon Forsbergâ¦
May 14 at 15:18
@SimonForsberg I don't see how that forces an explosion of code. Just start with
if ( isDivisibleBy(x, 15) ) return "Quack";
and the rest still works. The pattern is to treat prime numbers and compound numbers differently.â candied_orange
May 14 at 18:16
@SimonForsberg I don't see how that forces an explosion of code. Just start with
if ( isDivisibleBy(x, 15) ) return "Quack";
and the rest still works. The pattern is to treat prime numbers and compound numbers differently.â candied_orange
May 14 at 18:16
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f194188%2ffizz-buzz-test-driven-development%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password