Will Price Posts About

Beginner's steps with TDD

Jason Gorman has agreed to mentor me in the subject of TDD (Test Driven Development). I plan to document my progress as I learn the principles behind this philosophy.

TDD can be roughly outlined as follows:

  • Write a failing test for the desired functionality.
  • Write the smallest amount of code that can make that test pass.
  • Refactor you code, making sure your changes don’t break functionality (keep running the tests)

As my first introduction to TDD Jason and I did some pair programming where I implemented a simple Fibonacci function, this enabled me to see how the general principle worked: “Test a little, program a little”, and see what sort of obstacles I might come across, such as “What’s the next test going to be where there is no linear progression to follow”.

I’ve given my self a quick crash course in git to document my progress, I can commit every time I write a test or a piece of code. The history of the code can be viewed using gitk filename using a GUI or git log --follow --all -p filename[1].

I don’t have the commit history for the very first Fibonacci sequence exercise I did, however I’ve got my third attempt at it (it’s pretty similar to the first, I’ve just been trying to internalize the concepts I’ve met so far).

commit 9c764e57c26e43a87954fbc9026119530c2b6ecf
Author: Will Price <will.price94@gmail.com>
Date:   Tue Jan 29 17:56:42 2013 +0000

    Rename testLengthOf51 -> testLengthOfFiftyOne for consistency

diff --git a/fibonacci.py b/fibonacci.py
index b6d3197..dc28f8c 100755
--- a/fibonacci.py
+++ b/fibonacci.py
@@ -39,7 +39,7 @@ class TestFibonacciGenerator(unittest.TestCase):
     def testLengthOfSeven(self):
         self.assertRaises(ValueError, self.fibonacciGenerator, 7)
 
-    def testLengthOf51(self):
+    def testLengthOfFiftyOne(self):
         self.assertRaises(ValueError, self.fibonacciGenerator, 51)
 
 if __name__ == '__main__':

commit b73e6566b457ae493195ab04d8baf2bf5cfaf1bf
Author: Will Price <will.price94@gmail.com>
Date:   Tue Jan 29 17:56:13 2013 +0000

    Code to pass testLengthOf51

diff --git a/fibonacci.py b/fibonacci.py
index d3df5a9..b6d3197 100755
--- a/fibonacci.py
+++ b/fibonacci.py
@@ -4,7 +4,7 @@ import unittest
 
 class TestFibonacciGenerator(unittest.TestCase):
     def fibonacciGenerator(self, length):
-        if (length < 8):
+        if (length < 8 or length > 50):
             raise ValueError
 
         fibonacciSequence = [0, 1]
@@ -39,5 +39,8 @@ class TestFibonacciGenerator(unittest.TestCase):
     def testLengthOfSeven(self):
         self.assertRaises(ValueError, self.fibonacciGenerator, 7)
 
+    def testLengthOf51(self):
+        self.assertRaises(ValueError, self.fibonacciGenerator, 51)
+
 if __name__ == '__main__':
     unittest.main()

commit 67062b240b5d25631fd8d87fc2aeb3ae5e9b983e
Author: Will Price <will.price94@gmail.com>
Date:   Tue Jan 29 17:54:41 2013 +0000

    Code to pass TestLengthOfSeven

diff --git a/fibonacci.py b/fibonacci.py
index fcd695d..d3df5a9 100755
--- a/fibonacci.py
+++ b/fibonacci.py
@@ -4,6 +4,9 @@ import unittest
 
 class TestFibonacciGenerator(unittest.TestCase):
     def fibonacciGenerator(self, length):
+        if (length < 8):
+            raise ValueError
+
         fibonacciSequence = [0, 1]
 
         for i in range(2, length):

commit c313448c856360f009864e4c54d0fb25b47143ef
Author: Will Price <will.price94@gmail.com>
Date:   Tue Jan 29 17:53:56 2013 +0000

    Test for length of 7 (invalid)

diff --git a/fibonacci.py b/fibonacci.py
index 274d12b..fcd695d 100755
--- a/fibonacci.py
+++ b/fibonacci.py
@@ -33,5 +33,8 @@ class TestFibonacciGenerator(unittest.TestCase):
     def testValidLength(self):
         self.assertEquals(8, len(self.fibonacciGenerator(8)))
 
+    def testLengthOfSeven(self):
+        self.assertRaises(ValueError, self.fibonacciGenerator, 7)
+
 if __name__ == '__main__':
     unittest.main()

commit 0ad4ec5dd3a1df92fe40afb608f62ac7c8c52cda
Author: Will Price <will.price94@gmail.com>
Date:   Tue Jan 29 17:50:05 2013 +0000

    Changed testLength to testValidLength for clarity

diff --git a/fibonacci.py b/fibonacci.py
index 61f6f9a..274d12b 100755
--- a/fibonacci.py
+++ b/fibonacci.py
@@ -30,7 +30,8 @@ class TestFibonacciGenerator(unittest.TestCase):
     def testSixthNumber(self):
         self.assertEquals(5, self.fibonacciGenerator(8)[5])
 
-    def testLength(self):
+    def testValidLength(self):
         self.assertEquals(8, len(self.fibonacciGenerator(8)))
+
 if __name__ == '__main__':
     unittest.main()

commit f3c473f0fdd0d3e21f23efcf0916ea188a08f44c
Author: Will Price <will.price94@gmail.com>
Date:   Tue Jan 29 17:49:13 2013 +0000

    Test length of list

diff --git a/fibonacci.py b/fibonacci.py
index 783b800..61f6f9a 100755
--- a/fibonacci.py
+++ b/fibonacci.py
@@ -7,7 +7,7 @@ class TestFibonacciGenerator(unittest.TestCase):
         fibonacciSequence = [0, 1]
 
         for i in range(2, length):
-            fibonacciSequence.append(fibonacciSequence[i-2] + fibonacciSequence[i-1])
+            fibonacciSequence.append(fibonacciSequence[i - 2] + fibonacciSequence[i - 1])
 
         return fibonacciSequence
 
@@ -29,5 +29,8 @@ class TestFibonacciGenerator(unittest.TestCase):
 
     def testSixthNumber(self):
         self.assertEquals(5, self.fibonacciGenerator(8)[5])
+
+    def testLength(self):
+        self.assertEquals(8, len(self.fibonacciGenerator(8)))
 if __name__ == '__main__':
     unittest.main()

commit 1130cea31b30924f49fe49f3042da45a2825a460
Author: Will Price <will.price94@gmail.com>
Date:   Tue Jan 29 17:47:05 2013 +0000

    Test 6th number + code for that

diff --git a/fibonacci.py b/fibonacci.py
index f1b21d9..783b800 100755
--- a/fibonacci.py
+++ b/fibonacci.py
@@ -5,8 +5,10 @@ import unittest
 class TestFibonacciGenerator(unittest.TestCase):
     def fibonacciGenerator(self, length):
         fibonacciSequence = [0, 1]
+
         for i in range(2, length):
-            fibonacciSequence.append(i - 1)
+            fibonacciSequence.append(fibonacciSequence[i-2] + fibonacciSequence[i-1])
+
         return fibonacciSequence
 
     # TESTS
@@ -24,5 +26,8 @@ class TestFibonacciGenerator(unittest.TestCase):
 
     def testFifthNumber(self):
         self.assertEquals(3, self.fibonacciGenerator(8)[4])
+
+    def testSixthNumber(self):
+        self.assertEquals(5, self.fibonacciGenerator(8)[5])
 if __name__ == '__main__':
     unittest.main()

commit d0256181239d47d8d975eed0bfb4277fb7a78ae2
Author: Will Price <will.price94@gmail.com>
Date:   Tue Jan 29 17:40:18 2013 +0000

    Test fifth number, no code needed to pass

diff --git a/fibonacci.py b/fibonacci.py
index 3400d82..f1b21d9 100755
--- a/fibonacci.py
+++ b/fibonacci.py
@@ -22,5 +22,7 @@ class TestFibonacciGenerator(unittest.TestCase):
     def testFourthNumber(self):
         self.assertEquals(2, self.fibonacciGenerator(8)[3])
 
+    def testFifthNumber(self):
+        self.assertEquals(3, self.fibonacciGenerator(8)[4])
 if __name__ == '__main__':
     unittest.main()

commit 92b636a26292f1e78078652c039347bca2027321
Author: Will Price <will.price94@gmail.com>
Date:   Tue Jan 29 17:36:11 2013 +0000

    Test fourth number, no code needed to pass

diff --git a/fibonacci.py b/fibonacci.py
index c43b118..3400d82 100755
--- a/fibonacci.py
+++ b/fibonacci.py
@@ -19,5 +19,8 @@ class TestFibonacciGenerator(unittest.TestCase):
     def testThirdNumber(self):
         self.assertEquals(1, self.fibonacciGenerator(8)[2])
 
+    def testFourthNumber(self):
+        self.assertEquals(2, self.fibonacciGenerator(8)[3])
+
 if __name__ == '__main__':
     unittest.main()

commit 08b1e5edc66858f2205e16f32875706e06a128e6
Author: Will Price <will.price94@gmail.com>
Date:   Tue Jan 29 17:35:02 2013 +0000

    Code for third test

diff --git a/fibonacci.py b/fibonacci.py
index 28ed083..c43b118 100755
--- a/fibonacci.py
+++ b/fibonacci.py
@@ -4,8 +4,12 @@ import unittest
 
 class TestFibonacciGenerator(unittest.TestCase):
     def fibonacciGenerator(self, length):
-        return [0, 1]
+        fibonacciSequence = [0, 1]
+        for i in range(2, length):
+            fibonacciSequence.append(i - 1)
+        return fibonacciSequence
 
+    # TESTS
     def testFirstNumber(self):
         self.assertEquals(0, self.fibonacciGenerator(8)[0])
 

commit a5f3e527cdc205afeaf8df930534304a991091bd
Author: Will Price <will.price94@gmail.com>
Date:   Tue Jan 29 14:59:51 2013 +0000

    Add code for passing second test, test for third number

diff --git a/fibonacci.py b/fibonacci.py
index c9d28f3..28ed083 100755
--- a/fibonacci.py
+++ b/fibonacci.py
@@ -4,7 +4,7 @@ import unittest
 
 class TestFibonacciGenerator(unittest.TestCase):
     def fibonacciGenerator(self, length):
-        return [0]
+        return [0, 1]
 
     def testFirstNumber(self):
         self.assertEquals(0, self.fibonacciGenerator(8)[0])
@@ -12,6 +12,8 @@ class TestFibonacciGenerator(unittest.TestCase):
     def testSecondNumber(self):
         self.assertEquals(1, self.fibonacciGenerator(8)[1])
 
+    def testThirdNumber(self):
+        self.assertEquals(1, self.fibonacciGenerator(8)[2])
 
 if __name__ == '__main__':
     unittest.main()

commit f04d7ec901640e5771a4ae816f17fbfade9ee9af
Author: Will Price <will.price94@gmail.com>
Date:   Tue Jan 29 14:58:04 2013 +0000

    Code to pass first test, test for second number

diff --git a/fibonacci.py b/fibonacci.py
index 54fe5bf..c9d28f3 100755
--- a/fibonacci.py
+++ b/fibonacci.py
@@ -4,11 +4,14 @@ import unittest
 
 class TestFibonacciGenerator(unittest.TestCase):
     def fibonacciGenerator(self, length):
-        return [None]
+        return [0]
 
     def testFirstNumber(self):
         self.assertEquals(0, self.fibonacciGenerator(8)[0])
 
+    def testSecondNumber(self):
+        self.assertEquals(1, self.fibonacciGenerator(8)[1])
+
 
 if __name__ == '__main__':
     unittest.main()

commit a6a83808fb900638706ccfdbbe922b36f5e27d4d
Author: Will Price <will.price94@gmail.com>
Date:   Tue Jan 29 14:51:39 2013 +0000

    Testing first fibonacci number, implemented fibonacciGenerator function

diff --git a/fibonacci.py b/fibonacci.py
index f4dfbd8..54fe5bf 100755
--- a/fibonacci.py
+++ b/fibonacci.py
@@ -1,7 +1,14 @@
 #!/usr/bin/env python2
 import unittest
 
+
 class TestFibonacciGenerator(unittest.TestCase):
+    def fibonacciGenerator(self, length):
+        return [None]
+
+    def testFirstNumber(self):
+        self.assertEquals(0, self.fibonacciGenerator(8)[0])
+
 
 if __name__ == '__main__':
     unittest.main()

commit d8bbcd07a01cc3b84a006bb8546133604bed12ba
Author: Will Price <will.price94@gmail.com>
Date:   Tue Jan 29 10:16:20 2013 +0000

    Skeleton

diff --git a/fibonacci.py b/fibonacci.py
new file mode 100755
index 0000000..f4dfbd8
--- /dev/null
+++ b/fibonacci.py
@@ -0,0 +1,7 @@
+#!/usr/bin/env python2
+import unittest
+
+class TestFibonacciGenerator(unittest.TestCase):
+
+if __name__ == '__main__':
+    unittest.main()

You might disagree with my steps, or marvel at my crap commit messages; I’m just getting started with the tools and methodologies so hopefully in 6 months time I’ll be able to look back at this and correct all my mistakes.

I’ve been using tmux to organise my work, vim to edit it, git to save progress and watch to continually test my code (this is very handy!). I’m reasonably pleased with this workflow, it’s both simple and flexible. [1] - ‘–follow’ handles renames, ‘–all’ shows commits on all branches, ‘-p’ shows the changes in patch form (otherwise you just get commit messages)