author | Madhusudan.C.S <madhusudancs@gmail.com> |
Tue, 31 Aug 2010 18:57:30 +0530 | |
changeset 110 | 4e7b98636b58 |
parent 109 | 0afd25eadf41 |
child 112 | 0b01bb6ea6b8 |
permissions | -rw-r--r-- |
89
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
1 |
Fundamentals |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
2 |
============ |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
3 |
|
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
4 |
Test Driven Development, abbreviated as TDD is a method of software |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
5 |
development which banks on the idea of writing test cases that fail for the |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
6 |
code that doesn't even exist yet. The actual code is written later to pass |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
7 |
the test and then refactored. |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
8 |
|
109
0afd25eadf41
Add a section on real life tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
89
diff
changeset
|
9 |
First "Test" |
0afd25eadf41
Add a section on real life tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
89
diff
changeset
|
10 |
============ |
89
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
11 |
|
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
12 |
Writing a test is simple. Writing a failing test? It is much more simple. |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
13 |
Let us consider a very simple program which returns the Greatest Common |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
14 |
Divisor (GCD) of two numbers. Since the test cases for the code is written |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
15 |
prior to the code itself, it is necessary to have a clear idea of the code |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
16 |
units that our program will contain. Let us attempt to clearly define the |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
17 |
code units in our case of a GCD program. Let our program contain one and |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
18 |
only one function called gcd() which takes in two arguments as parameters. |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
19 |
These arguments are the numbers for which GCD must be computed. The gcd() |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
20 |
function returns a single value which is the GCD of the two arguments |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
21 |
passed. So if we want to find out GCD of 44, 23, I will call my code unit |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
22 |
as c = gcd(44, 23) where c will contain the GCD of those two numbers. |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
23 |
|
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
24 |
Now we have defined our code units, how will we write tests? Before writing |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
25 |
the test, a very fundamental question arises in our minds. How do tests |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
26 |
look like? So let us answer this question first. Tests are nothing but a |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
27 |
series of assertions which are either True or False depending on the |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
28 |
expected behaviour of the code. We tell our tests whether our code unit |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
29 |
asserts True or asserts False based on the expected behaviour of the code |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
30 |
units. If we happen to run the tests now we are sure to get errors. Oh! But |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
31 |
why? We don't even have the function gcd to call. The test code doesn't |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
32 |
even compile! So what should we do now? So the idea is to first write the |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
33 |
stubs for the code units before we start writing tests. This is necessary |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
34 |
for two reasons. Firstly, by writing the stubs for the code units we will |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
35 |
be able to correctly decide and fix on to the code units that we have |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
36 |
planned to include in our program. We have a clear cut idea as to how our |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
37 |
program is structured, how the tests must be written among other |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
38 |
things. Secondly, the tests must at least compile and then fail! If the |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
39 |
tests don't even compile, that doesn't mean the tests failed. It means |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
40 |
it was a failure on the programmer's part. Let us define our stub:: |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
41 |
|
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
42 |
def gcd(a, b): |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
43 |
pass |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
44 |
|
110
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
45 |
This stub does nothing other than defining a new function called gcd |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
46 |
which takes two parameters a and b for which the GCD must be |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
47 |
calculated. The body of the function just contains Python's **pass** |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
48 |
statement which means it does nothing, i.e. empty. We have our stub |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
49 |
ready. One important thing we need to keep in mind when we adopt TDD |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
50 |
methodology is that we need to have a clear set of results defined for |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
51 |
our code units. To put it more clearly, for every given set of inputs |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
52 |
as test case we must have, before hand, the exact outputs that are |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
53 |
expected for those input test cases. If we don't have that we have |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
54 |
failed in the first step of the TDD methodology itself. We must never |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
55 |
run looking for outputs for our test cases after we have the code |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
56 |
ready or even while writing tests. The expected outputs/behaviour must |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
57 |
be in our hands before we start writing tests. Therefore let us define |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
58 |
our test cases and the expected output for those inputs. Let one of |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
59 |
our test cases be 48 and 64 as *a* and *b* respectively. For this test |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
60 |
case we know that the GCD is 16. So that is the expected output. Let |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
61 |
our second test case be 44 and 19 as *a* and *b* respectively. We know |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
62 |
that their GCD is 1 by simple paper and pen calculation. |
89
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
63 |
|
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
64 |
Now we know what a test is? What are the ingredients required to write |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
65 |
tests? So what else should we wait for? Let us write our first test!:: |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
66 |
|
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
67 |
tc1 = gcd(48, 64) |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
68 |
if tc1 != 16: |
110
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
69 |
print "Test failed for the case a=48 and b=64. Expected 16. Obtained %d instead." % tc1 |
89
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
70 |
exit(1) |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
71 |
|
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
72 |
tc2 = gcd(44, 19) |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
73 |
if tc2 != 1: |
110
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
74 |
print "Test failed for the case a=44 and b=19. Expected 1. Obtained %d instead." % tc2 |
89
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
75 |
exit(1) |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
76 |
|
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
77 |
print "All tests passed!" |
109
0afd25eadf41
Add a section on real life tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
89
diff
changeset
|
78 |
|
110
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
79 |
Let us put all these in a file and call this file **gcd.py**:: |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
80 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
81 |
def gcd(a, b): |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
82 |
pass |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
83 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
84 |
if __name__ == '__main__': |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
85 |
tc1 = gcd(48, 64) |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
86 |
if tc1 != 16: |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
87 |
print "Test failed for the case a=48 and b=64. Expected 16. Obtained %d instead." % tc1 |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
88 |
exit(1) |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
89 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
90 |
tc2 = gcd(44, 19) |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
91 |
if tc2 != 1: |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
92 |
print "Test failed for the case a=44 and b=19. Expected 1. Obtained %d instead." % tc2 |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
93 |
exit(1) |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
94 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
95 |
print "All tests passed!" |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
96 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
97 |
Note that we have introduced a new semantic which uses two new magic names |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
98 |
in Python *__name__* and *__main__*. This is a very common idiom used in |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
99 |
Python. Every Python code in a file can be run in two ways: Either as an |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
100 |
independent stand-alone script or as a Python module which can be imported |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
101 |
by other Python scripts or modules. When the idiom:: |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
102 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
103 |
if __name__ == '__main__': |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
104 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
105 |
is used, the code within this if block is executed first when we run the |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
106 |
Python file as a stand-alone script. In other words, when we run this |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
107 |
python file as a stand-alone script the control of the program first starts |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
108 |
from the code that is within this if block from which the control is |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
109 |
transferred to other parts of the program or to other modules from |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
110 |
here. This comes as an extremely handy feature especially when we want to |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
111 |
test our modules individually. Now let us run our code as a stand-alone |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
112 |
script.:: |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
113 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
114 |
madhu@madhu:~/Desktop$ python gcd.py |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
115 |
Traceback (most recent call last): |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
116 |
File "gcd.py", line 7, in <module> print "Test failed for the case a=48 and b=64. Expected 16. Obtained %d instead." % tc1 |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
117 |
TypeError: %d format: a number is required, not NoneType |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
118 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
119 |
Now we have our tests, the test cases and the code unit stub at |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
120 |
hand. We also have the failing test. So we know for sure that we have |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
121 |
cleared the first check point of TDD where the tests have failed. The |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
122 |
failing tests also give a green signal for us to go ahead to our next |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
123 |
check point i.e. to write the actual code in our code unit and make |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
124 |
the test pass. So let us write the code for the gcd function by |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
125 |
removing the **pass** control statement which had just created a gcd |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
126 |
function stub for us. |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
127 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
128 |
Most of us have learnt in high school math classes that the best and |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
129 |
the easiest known algorithm to compute the gcd of two numbers was |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
130 |
given to us 2300 years ago by a greek mathematician named Euclid. So |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
131 |
let us use the Euclid's algorithm to compute the gcd of two numbers a |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
132 |
and b:: |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
133 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
134 |
def gcd(a, b): |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
135 |
if a == 0: |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
136 |
return b |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
137 |
while b != 0: |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
138 |
if a > b: |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
139 |
a = a - b |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
140 |
else: |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
141 |
b = b - a |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
142 |
return a |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
143 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
144 |
**Note**: If you are unaware of Euclidean algorithm to compute the gcd |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
145 |
of two numbers please refer to it on wikipedia. It has a very detailed |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
146 |
explanation of the algorithm and its proof of validity among other |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
147 |
things. |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
148 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
149 |
Now let us run our script which already has the tests written in it |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
150 |
and see what happens:: |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
151 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
152 |
madhu@madhu:/media/python/sttp/tdd$ python gcd.py |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
153 |
All tests passed! |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
154 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
155 |
Success! We managed to pass all the tests. But wasn't that code simple |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
156 |
enough? Indeed it was. If you take a closer look at the code you will |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
157 |
soon realize that the chain of subtraction operations can be replaced |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
158 |
by a modulo operation i.e. taking remainders of the division between |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
159 |
the two numbers since they are equivalent operations. Also modulo |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
160 |
operation is far better than chain of subtractions because you will |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
161 |
reduce much faster using modulo operation than the subtraction. For |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
162 |
example if let us take 25, 5 as a and b in our example. If we write |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
163 |
down the steps of the algorithm written above we have the following: |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
164 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
165 |
Step 1: a = 25 b = 5: Since both a and b are not 0 and b is greater |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
166 |
than a: b = 25 - 5 = 20 |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
167 |
Step 2: Since b is still not 0 and b is greater than a: b = 20 - 5 = |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
168 |
15 |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
169 |
Step 3: Since b is still not 0 and b is greater than a: b = 15 - 5 = |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
170 |
10 |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
171 |
Step 4: Since b is still not 0 and b is greater than a: b = 10 - 5 = 5 |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
172 |
Step 5: Since b is still not 0 and b is equal to a: b = 5 - 5 = 0 |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
173 |
Step 6: Since b is 0 the gcd is a = 5 which is returned |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
174 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
175 |
If we adopt the modulo operation instead of subtraction and follow the |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
176 |
steps: |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
177 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
178 |
Step 1: a = 25 b = 5: Since both a and b are not 0 and b is greater |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
179 |
than a: b = 25 % 5 = 0 |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
180 |
Step 2: Since b is 0 the gcd is a = 5 which is returned |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
181 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
182 |
Wow! That was overwhelmingly lesser number of steps! So now we are |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
183 |
convinced that if we replace the subtraction operation with the modulo |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
184 |
operation our code performs much better. But if we think carefully we |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
185 |
know that the modulo of a and b is less than b irrespective of how |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
186 |
large the value of a is, including the case where a is already less |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
187 |
than b. So we can eliminate that extra conditional **if** statement by |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
188 |
just swapping the result of the modulo operation to the position of b |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
189 |
and b to the position of a. This ensures that a is always greater than |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
190 |
b and if not the swapping combined with modulo operation takes care of |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
191 |
it. To exemplify it, if a = 5 and b = 25 then by swapping and |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
192 |
performing modulo we have a = b = 25 and b = a % b = 5 % 25 = 5 and |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
193 |
hence we proceed. So let us replace our original code with this new |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
194 |
improved code we have come up with simple observations:: |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
195 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
196 |
def gcd(a, b): |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
197 |
while b != 0: |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
198 |
a, b = b, a % b |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
199 |
return a |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
200 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
201 |
Executing our script again we will see that all the tests pass. One |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
202 |
final improvement we can think of which is not necessary in terms of |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
203 |
efficiency but is certainly good to do keeping in mind the readability |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
204 |
is that we can use the concept of recursion for the same |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
205 |
algorithm. Without going into much detail this is how the code looks |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
206 |
if we use a recursive approach:: |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
207 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
208 |
def gcd(a, b): |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
209 |
if b == 0: |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
210 |
return a |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
211 |
return gcd(b, a%b) |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
212 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
213 |
Much shorter and sweeter! And it passes all the tests! |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
214 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
215 |
|
109
0afd25eadf41
Add a section on real life tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
89
diff
changeset
|
216 |
More realistic "Tests" |
0afd25eadf41
Add a section on real life tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
89
diff
changeset
|
217 |
====================== |
0afd25eadf41
Add a section on real life tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
89
diff
changeset
|
218 |
|
0afd25eadf41
Add a section on real life tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
89
diff
changeset
|
219 |
Now we have completed writing our first test. Let us start writing tests |
0afd25eadf41
Add a section on real life tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
89
diff
changeset
|
220 |
for more realistic |