author | Madhusudan.C.S <madhusudancs@gmail.com> |
Tue, 07 Sep 2010 16:49:56 +0530 | |
changeset 129 | 6e237b9442cd |
parent 120 | 7428e411bd7a |
child 131 | 8888712bed39 |
permissions | -rw-r--r-- |
116
958e2e9f2858
Adding the page header. Better late than never.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
115
diff
changeset
|
1 |
======================= |
958e2e9f2858
Adding the page header. Better late than never.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
115
diff
changeset
|
2 |
Test Driven Development |
958e2e9f2858
Adding the page header. Better late than never.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
115
diff
changeset
|
3 |
======================= |
958e2e9f2858
Adding the page header. Better late than never.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
115
diff
changeset
|
4 |
|
89
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
5 |
Fundamentals |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
6 |
============ |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
7 |
|
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
8 |
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
|
9 |
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
|
10 |
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
|
11 |
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
|
12 |
|
109
0afd25eadf41
Add a section on real life tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
89
diff
changeset
|
13 |
First "Test" |
0afd25eadf41
Add a section on real life tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
89
diff
changeset
|
14 |
============ |
89
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
15 |
|
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
16 |
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
|
17 |
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
|
18 |
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
|
19 |
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
|
20 |
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
|
21 |
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
|
22 |
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
|
23 |
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
|
24 |
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
|
25 |
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
|
26 |
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
|
27 |
|
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
28 |
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
|
29 |
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
|
30 |
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
|
31 |
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
|
32 |
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
|
33 |
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
|
34 |
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
|
35 |
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
|
36 |
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
|
37 |
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
|
38 |
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
|
39 |
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
|
40 |
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
|
41 |
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
|
42 |
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
|
43 |
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
|
44 |
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
|
45 |
|
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
46 |
def gcd(a, b): |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
47 |
pass |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
48 |
|
110
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
49 |
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
|
50 |
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
|
51 |
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
|
52 |
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
|
53 |
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
|
54 |
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
|
55 |
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
|
56 |
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
|
57 |
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
|
58 |
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
|
59 |
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
|
60 |
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
|
61 |
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
|
62 |
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
|
63 |
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
|
64 |
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
|
65 |
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
|
66 |
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
|
67 |
|
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
68 |
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
|
69 |
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
|
70 |
|
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
71 |
tc1 = gcd(48, 64) |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
72 |
if tc1 != 16: |
110
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
73 |
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
|
74 |
exit(1) |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
75 |
|
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
76 |
tc2 = gcd(44, 19) |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
77 |
if tc2 != 1: |
110
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
78 |
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
|
79 |
exit(1) |
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
80 |
|
449760bc4089
Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff
changeset
|
81 |
print "All tests passed!" |
109
0afd25eadf41
Add a section on real life tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
89
diff
changeset
|
82 |
|
110
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
83 |
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
|
84 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
85 |
def gcd(a, b): |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
86 |
pass |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
87 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
88 |
if __name__ == '__main__': |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
89 |
tc1 = gcd(48, 64) |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
90 |
if tc1 != 16: |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
91 |
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
|
92 |
exit(1) |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
93 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
94 |
tc2 = gcd(44, 19) |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
95 |
if tc2 != 1: |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
96 |
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
|
97 |
exit(1) |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
98 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
99 |
print "All tests passed!" |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
100 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
101 |
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
|
102 |
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
|
103 |
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
|
104 |
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
|
105 |
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
|
106 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
107 |
if __name__ == '__main__': |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
108 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
109 |
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
|
110 |
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
|
111 |
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
|
112 |
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
|
113 |
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
|
114 |
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
|
115 |
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
|
116 |
script.:: |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
117 |
|
120
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
118 |
$ python gcd.py |
110
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
119 |
Traceback (most recent call last): |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
120 |
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
|
121 |
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
|
122 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
123 |
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
|
124 |
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
|
125 |
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
|
126 |
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
|
127 |
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
|
128 |
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
|
129 |
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
|
130 |
function stub for us. |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
131 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
132 |
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
|
133 |
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
|
134 |
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
|
135 |
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
|
136 |
and b:: |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
137 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
138 |
def gcd(a, b): |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
139 |
if a == 0: |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
140 |
return b |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
141 |
while b != 0: |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
142 |
if a > b: |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
143 |
a = a - b |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
144 |
else: |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
145 |
b = b - a |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
146 |
return a |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
147 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
148 |
**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
|
149 |
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
|
150 |
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
|
151 |
things. |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
152 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
153 |
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
|
154 |
and see what happens:: |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
155 |
|
120
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
156 |
$ python gcd.py |
110
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
157 |
All tests passed! |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
158 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
159 |
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
|
160 |
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
|
161 |
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
|
162 |
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
|
163 |
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
|
164 |
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
|
165 |
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
|
166 |
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
|
167 |
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
|
168 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
169 |
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
|
170 |
than a: b = 25 - 5 = 20 |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
171 |
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
|
172 |
15 |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
173 |
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
|
174 |
10 |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
175 |
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
|
176 |
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
|
177 |
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
|
178 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
179 |
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
|
180 |
steps: |
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 |
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
|
183 |
than a: b = 25 % 5 = 0 |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
184 |
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
|
185 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
186 |
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
|
187 |
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
|
188 |
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
|
189 |
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
|
190 |
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
|
191 |
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
|
192 |
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
|
193 |
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
|
194 |
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
|
195 |
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
|
196 |
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
|
197 |
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
|
198 |
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
|
199 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
200 |
def gcd(a, b): |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
201 |
while b != 0: |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
202 |
a, b = b, a % b |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
203 |
return a |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
204 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
205 |
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
|
206 |
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
|
207 |
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
|
208 |
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
|
209 |
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
|
210 |
if we use a recursive approach:: |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
211 |
|
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
212 |
def gcd(a, b): |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
213 |
if b == 0: |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
214 |
return a |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
215 |
return gcd(b, a%b) |
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
216 |
|
117
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
217 |
Much shorter and sweeter! And it passes all the tests! But there is |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
218 |
one small problem yet. For the users of this function there is no way |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
219 |
to determine how to use it, how many parameters it takes what it |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
220 |
returns among other things. And same as well for those who read the |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
221 |
code. So this function is not a very well written piece of code since |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
222 |
it lacks documentation. So to make this function mode readable let us |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
223 |
add the docstring for this function. Rewriting the function with the |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
224 |
docstring looks like this:: |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
225 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
226 |
def gcd(a, b): |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
227 |
"""Returns the Greatest Common Divisor of the two integers |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
228 |
passed as arguments. |
110
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
229 |
|
117
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
230 |
Args: |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
231 |
a: an integer |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
232 |
b: another integer |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
233 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
234 |
Returns: Greatest Common Divisor of a and b |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
235 |
""" |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
236 |
if b == 0: |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
237 |
return a |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
238 |
return gcd(b, a%b) |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
239 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
240 |
Now we have refactored our code enough to make it well written piece |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
241 |
of code. Let us move on. |
110
4e7b98636b58
Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
109
diff
changeset
|
242 |
|
109
0afd25eadf41
Add a section on real life tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
89
diff
changeset
|
243 |
More realistic "Tests" |
0afd25eadf41
Add a section on real life tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
89
diff
changeset
|
244 |
====================== |
0afd25eadf41
Add a section on real life tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
89
diff
changeset
|
245 |
|
112
0b01bb6ea6b8
Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
110
diff
changeset
|
246 |
Now we have successfully completed writing our first test, writing the |
0b01bb6ea6b8
Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
110
diff
changeset
|
247 |
relevant code and ensured the tests passed. We also refactored our |
0b01bb6ea6b8
Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
110
diff
changeset
|
248 |
code to perform better. With the knowledge of all these and some |
0b01bb6ea6b8
Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
110
diff
changeset
|
249 |
concepts and semantics like __main__ magic names we learnt we have |
0b01bb6ea6b8
Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
110
diff
changeset
|
250 |
come a long way with respect to writing tests. But our thirst is still |
0b01bb6ea6b8
Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
110
diff
changeset
|
251 |
unquenched! We want to do more and more tests! Not just write better |
0b01bb6ea6b8
Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
110
diff
changeset
|
252 |
code but also better tests! So let us keep building upon what we have |
0b01bb6ea6b8
Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
110
diff
changeset
|
253 |
learnt so far. |
0b01bb6ea6b8
Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
110
diff
changeset
|
254 |
|
115
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
255 |
Let us start writing tests for more realistic test cases. Generally |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
256 |
tests are predetermined as said above, if not the software design in |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
257 |
itself is flawed. The predetermined tests are stored along with the |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
258 |
test code in some persistent format like in a database, a text file, a |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
259 |
file of specific format like XML or in some other way. Let us continue |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
260 |
with our example of GCD function. We will keep all our test cases in a |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
261 |
text file, which is indeed persistent. Let us specify the format of |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
262 |
the test data in our file as follows. |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
263 |
|
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
264 |
1. The file has multiple lines of test data. |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
265 |
2. Each line in this file corresponds to a single test case. |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
266 |
3. Each line consists of three comma separated coloumns: |
112
0b01bb6ea6b8
Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
110
diff
changeset
|
267 |
|
115
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
268 |
i. First two coloumns are the integers for which the GCD has to |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
269 |
be computed |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
270 |
ii. Third coloumn is the expected GCD to the preceding two |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
271 |
numbers. |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
272 |
|
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
273 |
So how do we write our tests to use these test cases? Pretty simple, let |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
274 |
us review the machinery required first. |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
275 |
|
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
276 |
1. File reading: We already have learnt this in the modules on |
112
0b01bb6ea6b8
Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
110
diff
changeset
|
277 |
Basic Python. |
115
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
278 |
2. Parsing the read data from the file: This just involves a using a |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
279 |
**for** loop which iterates over the data line by line since we |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
280 |
know that the file contains each test case as a sepate line which |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
281 |
are equivalent to the file records and hence parse the data line |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
282 |
by line as strings as we iterate over it and convert it to the |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
283 |
required data type. |
112
0b01bb6ea6b8
Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
110
diff
changeset
|
284 |
|
0b01bb6ea6b8
Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
110
diff
changeset
|
285 |
Since we already have all the machinery required, let us proceed writing |
115
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
286 |
our test cases. We do not need not make any changes to the gcd |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
287 |
function so we will just write down the test here. Let us call our |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
288 |
data file gcd_testcases.dat:: |
112
0b01bb6ea6b8
Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
110
diff
changeset
|
289 |
|
115
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
290 |
if __name__ == '__main__': |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
291 |
for line in open('gcd_testcases.dat'): |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
292 |
values = line.split(', ') |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
293 |
a = int(values[0]) |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
294 |
b = int(values[1]) |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
295 |
g = int(values[2]) |
112
0b01bb6ea6b8
Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
110
diff
changeset
|
296 |
|
115
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
297 |
tc = gcd(a, b) |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
298 |
if tc != g: |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
299 |
print "Test failed for the case a=%d and b=%d. Expected %d. Obtained %d instead." % (a, b, g, tc) |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
300 |
exit(1) |
112
0b01bb6ea6b8
Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
110
diff
changeset
|
301 |
|
115
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
302 |
print "All tests passed!" |
112
0b01bb6ea6b8
Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
110
diff
changeset
|
303 |
|
115
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
304 |
When we execute the gcd.py script again we will notice that all the |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
305 |
tests passed. |
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
306 |
|
117
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
307 |
Python Testing Framework |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
308 |
======================== |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
309 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
310 |
Python provides two ways to test the code we have written. One of them |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
311 |
is the unittest framework and the the other is the doctest module. |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
312 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
313 |
doctest |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
314 |
~~~~~~~ |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
315 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
316 |
To start with let us discuss the doctest module. As we have already |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
317 |
discussed a well written piece of code must always be accompanied by |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
318 |
its documentation. For a function or a module we document them in their |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
319 |
respective docstrings. In addition to this, we can also place the |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
320 |
samples of using these functions or modules in the Python interactive |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
321 |
interpreter in the docstrings. When we run the doctest module it picks |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
322 |
up all such interactive session samples, executes them and determines |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
323 |
if the documented piece of code runs as it is documented. Let us see |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
324 |
how to write doctests for our gcd function:: |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
325 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
326 |
def gcd(a, b): |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
327 |
"""Returns the Greatest Common Divisor of the two integers |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
328 |
passed as arguments. |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
329 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
330 |
Args: |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
331 |
a: an integer |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
332 |
b: another integer |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
333 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
334 |
Returns: Greatest Common Divisor of a and b |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
335 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
336 |
>>> gcd(48, 64) |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
337 |
16 |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
338 |
>>> gcd(44, 19) |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
339 |
1 |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
340 |
""" |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
341 |
if b == 0: |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
342 |
return a |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
343 |
return gcd(b, a%b) |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
344 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
345 |
This is all a doctest is. To explain it in more simple terms tests |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
346 |
which are written as part of the docstrings are called as |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
347 |
doctests. Now how do we use our doctest module to execute this |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
348 |
tests. That is fairly straight forward as well. All we need to do is |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
349 |
tell the doctest module to execute. Let us place this piece of code at |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
350 |
the same place where we placed our tests earlier. So putting all these |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
351 |
together we have our gcd.py module which looks as follows:: |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
352 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
353 |
def gcd(a, b): |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
354 |
"""Returns the Greatest Common Divisor of the two integers |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
355 |
passed as arguments. |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
356 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
357 |
Args: |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
358 |
a: an integer |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
359 |
b: another integer |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
360 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
361 |
Returns: Greatest Common Divisor of a and b |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
362 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
363 |
>>> gcd(48, 64) |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
364 |
16 |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
365 |
>>> gcd(44, 19) |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
366 |
1 |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
367 |
""" |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
368 |
if b == 0: |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
369 |
return a |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
370 |
return gcd(b, a%b) |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
371 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
372 |
if __name__ == "__main__": |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
373 |
import doctest |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
374 |
doctest.testmod() |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
375 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
376 |
All we need to do is import the doctest module that is part of the |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
377 |
Python's standard library. Call the testmod() function in this |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
378 |
module. This function automatically checks for all the docstrings that |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
379 |
have sample sessions from the interactive interpreter, if they exist |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
380 |
it executes them and compares the output with the results as specified |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
381 |
in the sample sessions. It complains if the results don't match as |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
382 |
documented. When we execute this script as a stand-alone script we |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
383 |
will get back the prompt with no messages which means all the tests |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
384 |
passed:: |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
385 |
|
120
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
386 |
$ python gcd.py |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
387 |
$ |
117
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
388 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
389 |
If we further want to get a more detailed report of the tests that |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
390 |
were executed we can run python with -v as the command line option |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
391 |
to the script:: |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
392 |
|
120
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
393 |
$ python gcd.py -v |
117
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
394 |
Trying: |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
395 |
gcd(48, 64) |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
396 |
Expecting: |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
397 |
16 |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
398 |
ok |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
399 |
Trying: |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
400 |
gcd(44, 19) |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
401 |
Expecting: |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
402 |
1 |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
403 |
ok |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
404 |
1 items had no tests: |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
405 |
__main__ |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
406 |
1 items passed all tests: |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
407 |
2 tests in __main__.gcd |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
408 |
2 tests in 2 items. |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
409 |
2 passed and 0 failed. |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
410 |
Test passed. |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
411 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
412 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
413 |
**Note:** We can have the sample sessions as test cases as long as the |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
414 |
outputs of the test cases do not contain any blank lines. In such |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
415 |
cases we may have to use the exact string *<BLANKLINE>* |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
416 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
417 |
For the sake of illustrating a failing test case, let us assume that |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
418 |
we made a small mistake in our code. Instead of returning **a** when b |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
419 |
= 0 we typed it as return b when b = 0. So all the gcds returned will |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
420 |
have the value of 0 in such a piece of code. The code looks as |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
421 |
follows:: |
112
0b01bb6ea6b8
Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
110
diff
changeset
|
422 |
|
117
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
423 |
def gcd(a, b): |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
424 |
"""Returns the Greatest Common Divisor of the two integers |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
425 |
passed as arguments. |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
426 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
427 |
Args: |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
428 |
a: an integer |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
429 |
b: another integer |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
430 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
431 |
Returns: Greatest Common Divisor of a and b |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
432 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
433 |
>>> gcd(48, 64) |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
434 |
16 |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
435 |
>>> gcd(44, 19) |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
436 |
1 |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
437 |
""" |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
438 |
if b == 0: |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
439 |
return a |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
440 |
return gcd(b, a%b) |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
441 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
442 |
Executing this code snippet without -v option to the script:: |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
443 |
|
120
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
444 |
$ python gcd.py |
117
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
445 |
********************************************************************** |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
446 |
File "gcd.py", line 11, in __main__.gcd |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
447 |
Failed example: |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
448 |
gcd(48, 64) |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
449 |
Expected: |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
450 |
16 |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
451 |
Got: |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
452 |
0 |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
453 |
********************************************************************** |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
454 |
File "gcd.py", line 13, in __main__.gcd |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
455 |
Failed example: |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
456 |
gcd(44, 19) |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
457 |
Expected: |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
458 |
1 |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
459 |
Got: |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
460 |
0 |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
461 |
********************************************************************** |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
462 |
1 items had failures: |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
463 |
2 of 2 in __main__.gcd |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
464 |
***Test Failed*** 2 failures. |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
465 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
466 |
The output clearly complains that there were exactly two test cases |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
467 |
that failed. If we want a more verbose report we can pass -v option to |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
468 |
the script. This is pretty much about the doctest module in |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
469 |
Python. doctest is extremely useful when we want to test each Python |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
470 |
function or module individually. For more information about the |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
471 |
doctest module refer to the Python library reference on doctest[0]. |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
472 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
473 |
unittest framework |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
474 |
~~~~~~~~~~~~~~~~~~ |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
475 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
476 |
Not too far ahead we go we, we will start complaining that the doctest |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
477 |
is not sufficient to write complicated tests especially when we want |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
478 |
to automate our tests, write tests that need to test for more |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
479 |
convoluted code pieces. For such scenarios Python provides a unittest |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
480 |
framework. unittest framework provides methods to efficiently |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
481 |
automate tests, setup and teardown functionalities which helps to |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
482 |
setup the initializing code and data for executing the specific tests |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
483 |
and cleanly shutting them down once the tests are executed and ways to |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
484 |
aggregate tests into collections and better way of reporting the |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
485 |
tests. |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
486 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
487 |
Let us continue testing our gcd function in the Python module named |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
488 |
gcd.py. To get ourselves started, the unittest framework expects us to |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
489 |
subclass TestCase class in unittest module and place all our test code |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
490 |
as methods of this class. We will begin the name of the test method |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
491 |
with **test_** so that the test runner knows which methods are to be |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
492 |
executed as tests. We will use the test cases supplied by |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
493 |
gcd_testcases.dat. Lastly, to illustrate the way to test Python code |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
494 |
as a module let create a new file called test_gcd.py following the |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
495 |
same convention used to name the test methods. We will place our test |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
496 |
code within test_gcd.py module. Our test code looks like this:: |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
497 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
498 |
import gcd |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
499 |
import unittest |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
500 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
501 |
class TestGcdFunction(unittest.TestCase): |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
502 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
503 |
def setUp(self): |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
504 |
self.test_file = open('gcd_testcases.dat') |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
505 |
self.test_cases = [] |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
506 |
for line in self.test_file: |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
507 |
values = line.split(', ') |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
508 |
a = int(values[0]) |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
509 |
b = int(values[1]) |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
510 |
g = int(values[2]) |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
511 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
512 |
self.test_cases.append([a, b, g]) |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
513 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
514 |
def test_gcd(self): |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
515 |
for case in self.test_cases: |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
516 |
a = case[0] |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
517 |
b = case[1] |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
518 |
g = case[2] |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
519 |
self.assertEqual(gcd.gcd(a, b), g) |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
520 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
521 |
def tearDown(self): |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
522 |
self.test_file.close() |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
523 |
del self.test_cases |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
524 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
525 |
if __name__ == '__main__': |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
526 |
unittest.main() |
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
527 |
|
120
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
528 |
Since we don't want to read this file into memory each time we run a |
117
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
529 |
separate test method, we will read all the data in the file into |
120
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
530 |
Python lists in the setUp method. The entire data file is kept in a |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
531 |
list called test_cases which happens to be an attribute of the |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
532 |
TestGCDFunction class. In the tearDown method of the class we |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
533 |
will delete this attribute to free up the memory and close the |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
534 |
opened file. |
117
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
535 |
|
120
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
536 |
Our actual test code sits in the method which begins with the name |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
537 |
**test_** as said earlier, the test_gcd method. Note that we import |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
538 |
the gcd Python module we have written at the top of this test file and |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
539 |
from this test method we call the gcd function within the gcd module |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
540 |
to be tested with the each set of **a** and **b** values in the |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
541 |
attribute test_cases. Once we execute the function we obtain the |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
542 |
result and compare it with the expected result as stored in the |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
543 |
corresponding test_cases attribute using the assertEqual methods |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
544 |
provided by our parent class TestCase in the unittest framework. There |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
545 |
are several other assertion methods supplied by the unittest |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
546 |
framework. For a more detailed information about this, refer to the |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
547 |
unittest library reference at [1]. |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
548 |
|
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
549 |
nose |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
550 |
==== |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
551 |
|
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
552 |
Now we know almost all the varities of tests we may have to use to |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
553 |
write self-sustained, automated tests for our code. There is one last |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
554 |
thing that is left. However one question remains, how do we easily |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
555 |
organize choose and run the tests that is scattered around several |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
556 |
files? |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
557 |
|
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
558 |
To further explain, the idea of placing tests with in the Python |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
559 |
scripts and executing that test scripts themselves as stand-alone |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
560 |
scripts works well as long as we have our code in a single Python file |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
561 |
or as long as the tests for each script can be run separately. But in |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
562 |
a more realistic software development scenario, often this is not the |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
563 |
case. The code is spread around multiple Python modules and may be |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
564 |
even across several Python packages. |
115
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
565 |
|
120
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
566 |
In such a such a scenario we wish we had a better tool to |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
567 |
automatically aggregate these tests and execute them. Fortunately for |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
568 |
us there exists a tool called nose. Although nose is not part of the |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
569 |
standard Python distribution itself, it can be very easily installed |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
570 |
by using easy_install command as follows:: |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
571 |
|
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
572 |
$ easy_install nose |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
573 |
|
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
574 |
Or download the nose package from [2], extracting the archive and |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
575 |
running the command from the extracted directory:: |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
576 |
|
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
577 |
$ python setup.py install |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
578 |
|
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
579 |
Now we have nose up and running, but how do we use it? It is very |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
580 |
straight forward as well. We will use the command provided by nose |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
581 |
called as nosetests. Run the following command in the top level |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
582 |
directory of your code:: |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
583 |
|
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
584 |
$ nosetests |
115
7455326cac40
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
112
diff
changeset
|
585 |
|
120
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
586 |
Thats all, nose automatically picks all the tests in all the |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
587 |
directories and subdirectories in our code base and executes them |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
588 |
all. However if we want to execute specific tests we can pass the test |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
589 |
file names or the directories as arguments to nosetests command. For a |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
590 |
detailed explanation about this, refer to [3] |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
591 |
|
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
592 |
Conclusion |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
593 |
========== |
117
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
594 |
|
120
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
595 |
Now we have all the trappings we want to write state-of-the art |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
596 |
tests. To emphasize the same point again, any code which was written |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
597 |
before writing the test and the testcases in hand is flawed by |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
598 |
design. So it is recommended to follow the three step approach while |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
599 |
writing code for any project as below: |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
600 |
|
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
601 |
1. Write failing tests with testcases in hand. |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
602 |
2. Write the code to pass the tests. |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
603 |
3. Refactor the code for better performance. |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
604 |
|
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
605 |
This approach is very famously known to the software development world |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
606 |
as "Red-Green-Refactor" approach[4]. |
117
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
607 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
608 |
|
fab0281a992f
Add materials on doctest and unittest framework.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
116
diff
changeset
|
609 |
[0] - http://docs.python.org/library/doctest.html |
120
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
610 |
[1] - http://docs.python.org/library/unittest.html |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
611 |
[2] - http://pypi.python.org/pypi/nose/ |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
612 |
[3] - http://somethingaboutorange.com/mrl/projects/nose/0.11.2/usage.html |
7428e411bd7a
Final portions of Test Driven Development.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
117
diff
changeset
|
613 |
[4] - http://en.wikipedia.org/wiki/Test-driven_development |