Writting FizzBuzz Kata

Writing Fizzbuzz Kata

In the current Tech era we must test our code as a unit test. TDD katas is a way to ensure that we are delivering good and stable/reliable code. Here we'll write a simple C# program and then write its Kata.

The followings are the basic requirements:

Write a program that prints the numbers from 1 to 100. But for multiples of three print "Fizz" instead of the number and for the multiples of five print "Buzz". For numbers that are multiples of both three and five print "FizzBuzz".

How to write the code

We need a procedure to write the program.

Let's divide this into the following multiple steps so we can easily write and test this:

  • Print numbers from 1 to 100
  • Print "Fizz" instead of the number that is divisible by 3
  • Print "Buzz" instead of the number that is divisible by 5
  • Print "FizzBuzz" instead of the number that is divisible by both 3 and 5

 

  1. public static string PrintFizzBuzz()    
  2.     
  3. {    
  4.     
  5. var resultFizzBuzz = string.Empty;    
  6.     
  7. resultFizzBuzz = GetNumbers(resultFizzBuzz);    
  8.     
  9. return resultFizzBuzz;    
  10.     
  11. }   
In the preceding, we wrote a simple PrintFizzBuzz() method that is doing the stuff. So, follow our procedure and the following is the complete code:
  1. public class FizzBuzz    
  2. {    
  3.     #region Public Methods    
  4.   
  5.      
  6.     public static string PrintFizzBuzz()    
  7.     {    
  8.         var resultFizzBuzz = string.Empty;    
  9.         resultFizzBuzz = GetNumbers(resultFizzBuzz);    
  10.         return resultFizzBuzz;    
  11.     }    
  12.     public static string PrintFizzBuzz(int number)    
  13.     {    
  14.         CanThrowArgumentExceptionWhenNumberNotInRule(number);    
  15.      
  16.         var result = GetFizzBuzzResult(number);    
  17.      
  18.         if (string.IsNullOrEmpty(result))    
  19.             result = GetFizzResult(number);    
  20.         if (string.IsNullOrEmpty(result))    
  21.             result = GetBuzzResult(number);    
  22.   
  23.         return string.IsNullOrEmpty(result) ? number.ToString(CultureInfo.InvariantCulture) : result;    
  24.     }    
  25.     #endregion    
  26.   
  27.     #region Private Methods    
  28.     private static string GetFizzBuzzResult(int number)    
  29.     {    
  30.         string result = null;    
  31.         if (IsFizz(number) && IsBuzz(number)) result = "FizzBuzz";    
  32.         return result;    
  33.     }    
  34.     
  35.     private static string GetBuzzResult(int number)    
  36.     {    
  37.         string result = null;    
  38.         if (IsBuzz(number)) result = "Buzz";    
  39.         return result;    
  40.     }    
  41.      
  42.     private static string GetFizzResult(int number)    
  43.     {    
  44.         string result = null;    
  45.         if (IsFizz(number)) result = "Fizz";    
  46.         return result;    
  47.     }    
  48.      
  49.     private static void CanThrowArgumentExceptionWhenNumberNotInRule(int number)    
  50.     {    
  51.         if (number > 100 || number < 1)    
  52.             throw new ArgumentException(    
  53.                 string.Format(    
  54.                     "entered number is [{0}], which does not meet rule, entered number should be between 1 to 100.", number));    
  55.     }    
  56.      
  57.     private static string GetNumbers(string resultFizzBuzz)    
  58.     {    
  59.      
  60.         for (var i = 1; i <= 100; i++)    
  61.         {    
  62.             var printNumber = string.Empty;    
  63.             if (IsFizz(i)) printNumber += "Fizz";    
  64.             if (IsBuzz(i)) printNumber += "Buzz";    
  65.             if (IsNumber(printNumber))    
  66.                 printNumber = (i).ToString(CultureInfo.InvariantCulture);    
  67.             resultFizzBuzz += " " + printNumber;    
  68.         }    
  69.         return resultFizzBuzz.Trim();    
  70.     }    
  71.     private static string GetNumbersUsingLinq(string resultFizzBuzz)    
  72.     {    
  73.         Enumerable.Range(1, 100)    
  74.             .Select(fb => String.Format("{0}{1}", fb % 3 == 0 ? "Fizz" : "", fb % 5 == 0 ? "Buzz" : ""))    
  75.             .Select(fb => fb != null ? (String.IsNullOrEmpty(fb) ? fb.ToString(CultureInfo.InvariantCulture) : fb) : null)    
  76.             .ToList()    
  77.             .ForEach(x => resultFizzBuzz = x);    
  78.         return resultFizzBuzz.Trim();    
  79.     }    
  80.     
  81.     private static bool IsNumber(string printNumber)    
  82.     {    
  83.         return String.IsNullOrEmpty(printNumber);    
  84.     }    
  85.    
  86.     private static bool IsBuzz(int i)    
  87.     {    
  88.         return i % 5 == 0;    
  89.     }    
  90.     
  91.     private static bool IsFizz(int i)    
  92.     {    
  93.         return i % 3 == 0;    
  94.     }    
  95.     #endregion    
  96. }  
How to write TDD

Please note that here we are following Red Green and the Refactor approach of Test Driven Develoment.

 

  • In Red stage: We pass the failed test
  • Green Stage: When the test has passed it is a green stage
  • Refactorin stage: Here we determine the possibilities to refactor the code.

The following are the tests:

  • Create a method to accept single number
  • Create test to verify supplied number within the range 1 to 100
  • Create test to verify number and return result Fizz or Buzz or FizzBuzz per above criteria

Here are the complete tests:

  1. using System;    
  2. using NUnit.Framework;    
  3.      
  4. namespace TDD_Katas_project.FizzBuzzKata    
  5. {    
  6.     [TestFixture]    
  7.     [Category("TheFizzBuzzKata")]    
  8.     public class TestFizzBuzz    
  9.     {    
  10.         #region Private members    
  11.         private string _resultFizz;    
  12.         #endregion    
  13.    
  14.         #region Setup/TearDown    
  15.         [TestFixtureSetUp]    
  16.         public void Setup()    
  17.         {    
  18.             _resultFizz = @"1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz Fizz 22 23 Fizz Buzz 26 Fizz 28 29 FizzBuzz 31 32 Fizz 34 Buzz Fizz 37 38 Fizz Buzz 41 Fizz 43 44 FizzBuzz 46 47 Fizz 49 Buzz Fizz 52 53 Fizz Buzz 56 Fizz 58 59 FizzBuzz 61 62 Fizz 64 Buzz Fizz 67 68 Fizz Buzz 71 Fizz 73 74 FizzBuzz 76 77 Fizz 79 Buzz Fizz 82 83 Fizz Buzz 86 Fizz 88 89 FizzBuzz 91 92 Fizz 94 Buzz Fizz 97 98 Fizz Buzz";    
  19.         }    
  20.         [TestFixtureTearDown]    
  21.         public void TearDown()    
  22.         {    
  23.             _resultFizz = null;    
  24.         }    
  25.         #endregion    
  26.    
  27.         #region Test Methods    
  28.      
  29.         [Test]    
  30.         public void CanTestFizz()    
  31.         {    
  32.             Console.WriteLine(FizzBuzz.PrintFizzBuzz());    
  33.             Assert.That(FizzBuzz.PrintFizzBuzz(), Is.EqualTo(_resultFizz));    
  34.         }    
  35.         [Test]    
  36.         [TestCase(-1)]    
  37.         [TestCase(101)]    
  38.         [TestCase(0)]    
  39.         public void CanThrowArgumentExceptionWhenSuppliedNumberDoesNotMeetRule(int number)    
  40.         {    
  41.             var exception = Assert.Throws<ArgumentException>(() => FizzBuzz.PrintFizzBuzz(number));    
  42.      
  43.             Assert.That(exception.Message, Is.EqualTo(string.Format("entered number is [{0}], which does not meet rule, entered number should be between 1 to 100.", number)));    
  44.      
  45.         }    
  46.         [Test]    
  47.         [TestCase(1, "1")]    
  48.         [TestCase(3, "Fizz")]    
  49.         [TestCase(5, "Buzz")]    
  50.         [TestCase(15, "FizzBuzz")]    
  51.         [TestCase(30, "FizzBuzz")]    
  52.         public void CanTestSingleNumber(int number, string expectedresult)    
  53.         {    
  54.             var actualresult = FizzBuzz.PrintFizzBuzz(number);    
  55.             Assert.That(actualresult, Is.EqualTo(expectedresult),    
  56.                              string.Format("result of entered number [{0}] is [{1}] but it should be [{2}]", number,    
  57.                                            actualresult, expectedresult));    
  58.         }    
  59.         #endregion    
  60.     }    
  61. }   
Please note that in the above we used the Nunit framework for TDD.

You can download the entire collection of TDDs from GitHub: https://github.com/garora/TDD-Katas.

 

Up Next
    Ebook Download
    View all
    Learn
    View all