Tuesday, August 10, 2010

TDD Example Write function that calcutates a Fibonacci number

Step 1:

   1:  [TestMethod]
   2:  public void FibonacciSequanceTest(){
   3:     Func<int, int> fib = null;
   4:   
   5:     Assert.AreEqual(0, fib(0));
   6:  }
Step 2:

   1:  [TestMethod]
   2:  public void FibonacciSequanceTest(){
   3:     Func<int, int> fib = (n) => { return n; };
   4:   
   5:     Assert.AreEqual(0, fib(0));
   6:  }
Wee first test case passed!
Step 3: Adding another testcase

   1:  [TestMethod]
   2:  public void FibonacciSequanceTest(){
   3:      Func<int, int> fib = (n) => { return n; };
   4:   
   5:   
   6:      Assert.AreEqual(0, fib(0));
   7:      Assert.AreEqual(1, fib(1));
   8:  }
Works again
Step 4: Removing duplication in the asserts
   1:  [TestMethod]
   2:  public void FibonacciSequanceTest(){
   3:      Func<int, int> fib = (n) => { return n; };
   4:   
   5:      Assert.AreEqual(0, fib(0));
   6:      Assert.AreEqual(1, fib(1));
   7:  }
Refactored gives:

   1:  [TestMethod]
   2:  public void FibonacciSequanceTest(){
   3:      Func<int, int> fib = (n) => {
   4:          return n;
   5:      };
   6:   
   7:      Dictionary<int, int> fibonacciSequence = new Dictionary<int, int>{
   8:                  {0 , 0},
   9:                  {1 , 1},
  10:              };
  11:   
  12:      foreach (KeyValuePair<int, int> row in fibonacciSequence)
  13:      {
  14:          Assert.AreEqual(row.Value, fib(row.Key));
  15:      }
  16:  }
Step 5: Adding another testcase

   1:  [TestMethod]
   2:  public void FibonacciSequanceTest(){
   3:      Func<int, int> fib = (n) => {
   4:          return n;
   5:      };
   6:   
   7:      Dictionary<int, int> fibonacciSequence = new Dictionary<int, int>{
   8:                  {0 , 0},
   9:                  {1 , 1},
  10:                  {2 , 1},
  11:              };
  12:   
  13:      foreach (KeyValuePair<int, int> row in fibonacciSequence)
  14:      {
  15:          Assert.AreEqual(row.Value, fib(row.Key));
  16:      }
  17:  }
Woops test failed!
Ok lets fix it:

   1:  [TestMethod]
   2:  public void FibonacciSequanceTest(){
   3:      Func<int, int> fib = (n) => {
   4:          if (n < 2) return n;
   5:          return 1;
   6:      };
   7:   
   8:      Dictionary<int, int> fibonacciSequence = new Dictionary<int, int>{
   9:                  {0 , 0},
  10:                  {1 , 1},
  11:                  {2 , 1},
  12:              };
  13:   
  14:      foreach (KeyValuePair<int, int> row in fibonacciSequence)
  15:      {
  16:          Assert.AreEqual(row.Value, fib(row.Key));
  17:      }
  18:  }
Test Fixed!
Step 6: Adding another test case and taking 2 steps at the time since 1 will never equal 2 but 1 = 2-1 and 2 = 3-1 and thus return n-1 will do the trick for now

   1:  [TestMethod]
   2:  public void FibonacciSequanceTest(){
   3:      Func<int, int> fib = (n) => {
   4:          if (n < 2) return n;
   5:          return n - 1;
   6:      };
   7:   
   8:      Dictionary<int, int> fibonacciSequence = new Dictionary<int, int>{
   9:                  {0 , 0},
  10:                  {1 , 1},
  11:                  {2 , 1},
  12:                  {3 , 2}
  13:              };
  14:   
  15:      foreach (KeyValuePair<int, int> row in fibonacciSequence)
  16:      {
  17:          Assert.AreEqual(row.Value, fib(row.Key));
  18:      }
  19:  }
 
 
Step 7: adding 2 more test cases (since the next we add will work fine too :))


   1:  [TestMethod]
   2:  public void FibonacciSequanceTest(){
   3:      Func<int, int> fib = (n) => {
   4:          if (n < 2) return n;
   5:          return n - 1;
   6:      };
   7:   
   8:      Dictionary<int, int> fibonacciSequence = new Dictionary<int, int>{
   9:                  {0 , 0},
  10:                  {1 , 1},
  11:                  {2 , 1},
  12:                  {3 , 2},
  13:                  {4 , 3},
  14:                  {5 , 5}
  15:              };
  16:   
  17:      foreach (KeyValuePair<int, int> row in fibonacciSequence)
  18:      {
  19:          Assert.AreEqual(row.Value, fib(row.Key));
  20:      }
  21:  }
Test Fails again (the test case marked in red)
The solution (fast forwarded):
Because 5 = 2 + 3
From the testcases we can see that fib(3) = 2 and fib(4)=3
And thus 5 = fib(3) + fib(4)
3 = 5 - 2 and 4 = 5 - 1
5 = n and this 5 = fib(n-2) + fib(n-1)

   1:  [TestMethod]
   2:  public void FibonacciSequanceTest(){
   3:      Func<int, int> fib = (n) => {
   4:          if (n < 2) return n;
   5:          return fib(n - 1) + fib(n - 2);
   6:      };
   7:   
   8:      Dictionary<int, int> fibonacciSequence = new Dictionary<int, int>{
   9:                  {0 , 0},
  10:                  {1 , 1},
  11:                  {2 , 1},
  12:                  {3 , 2},
  13:                  {4 , 3},
  14:                  {5 , 5}
  15:              };
  16:   
  17:      foreach (KeyValuePair<int, int> row in fibonacciSequence)
  18:      {
  19:          Assert.AreEqual(row.Value, fib(row.Key));
  20:      }
  21:  }
Does not compile :( Error: use of unsigned variable
The fix:
   1:  [TestMethod]
   2:  public void FibonacciSequanceTest(){
   3:      Func<int, int> fib = null;
   4:          fib = (n) => {
   5:          if (n < 2) return n;
   6:          return fib(n - 2) + fib(n - 1);
   7:      };
   8:   
   9:      Dictionary<int, int> fibonacciSequence = new Dictionary<int, int>{
  10:                  {0 , 0},
  11:                  {1 , 1},
  12:                  {2 , 1},
  13:                  {3 , 2},
  14:                  {4 , 3},
  15:                  {5 , 5}
  16:              };
  17:   
  18:      foreach (KeyValuePair<int, int> row in fibonacciSequence)
  19:      {
  20:          Assert.AreEqual(row.Value, fib(row.Key));
  21:      }
  22:  }

Et voila done!