1 .. Objectives |
|
2 .. ---------- |
|
3 |
|
4 .. Writing Simple Tests (Applying) |
|
5 .. Automating these tests |
|
6 .. Coding Style |
|
7 .. Errors and Exceptions |
|
8 |
|
9 .. Prerequisites |
|
10 .. ------------- |
|
11 |
|
12 .. 1. Getting started with functions |
|
13 .. 2. Advanced Features of Functions |
|
14 |
|
15 .. Author : Amit Sethi |
|
16 Internal Reviewer : |
|
17 External Reviewer : |
|
18 Checklist OK? : <put date stamp here, if OK> [2010-10-05] |
|
19 |
|
20 Script |
|
21 ------ |
|
22 |
|
23 {{{ Show the slide containing title }}} |
|
24 |
|
25 Hello Friends. Welcome to this tutorial on Testing and Debugging. |
|
26 |
|
27 {{{ Show the outline slide }}} |
|
28 |
|
29 In this tutorial we will learn. |
|
30 |
|
31 1.What software Testing is? |
|
32 2.Learn to test simple functions for their functionality. |
|
33 3.Learn how to automate tests. |
|
34 4.Need for coding style and some of the standards followed by the Python Community. |
|
35 5.Handling Errors and Exceptions. |
|
36 |
|
37 Software testing is an activity aimed at evaluating a program |
|
38 and determining that it meets its required results. |
|
39 |
|
40 {{{ Slide with the function }}} |
|
41 |
|
42 Lets first write a simple function to calculate gcd of two numbers.:: |
|
43 |
|
44 def gcd(a, b): |
|
45 if b == 0: |
|
46 return a |
|
47 return gcd(b, a%b) |
|
48 |
|
49 save this into a file "/home/fossee/gcd.py". |
|
50 |
|
51 Now we need to evaluate this function. Thus we have to check whether |
|
52 function successfully gives us the gcd of two whole numbers. Thus we need |
|
53 a set of inputs and the exact outputs that are expected for those input |
|
54 test cases. |
|
55 |
|
56 Let our test case be 48 and 64 as *a* and *b* respectively. For this test |
|
57 case we know that the GCD is 16. So that is the expected output. |
|
58 |
|
59 {{{ Slide with change in code }}} |
|
60 |
|
61 Let us include code for testing in our **gcd.py** file :: |
|
62 |
|
63 def gcd(a, b): |
|
64 if b == 0: |
|
65 return a |
|
66 return gcd(b, a%b) |
|
67 |
|
68 if __name__ == '__main__': |
|
69 result = gcd(48, 64) |
|
70 if result != 16: |
|
71 print "Test failed" |
|
72 print "Test Passed" |
|
73 |
|
74 Note that we have introduced a new semantic which uses two new magic names |
|
75 in Python *__name__* and *__main__*. This is a very common idiom used in |
|
76 Python. Every Python code in a file can be run in two ways: Either as an |
|
77 independent stand-alone script or as a Python module which can be imported |
|
78 by other Python scripts or modules. When the idiom:: |
|
79 |
|
80 if __name__ == '__main__': |
|
81 |
|
82 {{{ Slide with the idiom }}} |
|
83 |
|
84 |
|
85 is used, the code within this if block is executed first when we run the |
|
86 Python file as a stand-alone script. In other words, when we run this |
|
87 python file as a stand-alone script the control of the program first starts |
|
88 from the code that is within this if block from which the control is |
|
89 transferred to other parts of the program or to other modules from |
|
90 here. This comes as an extremely handy feature especially when we want to |
|
91 test our modules individually. |
|
92 |
|
93 But there can be a number of places where the gcd function might break would we |
|
94 have to right a seperate test case for all of them. |
|
95 |
|
96 Following is an (are) exercise(s) that you must do. |
|
97 |
|
98 %% %% Write code for lcm and write tests for it |
|
99 |
|
100 %% %% Answer is on the screen. |
|
101 |
|
102 Well thats where automating tests come in. We can run many tests to check where our |
|
103 code can break. Lets see this with an example. Lets try and automate tests on the |
|
104 gcd function. For this we will write a file with test cases and call the function |
|
105 for all of them. |
|
106 |
|
107 {{{ Slide with the structure of file }}} |
|
108 |
|
109 The structure of the file will be the two parameters and the output result seperated |
|
110 by space:: |
|
111 |
|
112 | 12 | 28 | 4 | |
|
113 | 18 | 36 | 18 | |
|
114 | 4678 | 39763 | 2339 | |
|
115 |
|
116 The file structure is shown in form a table here. |
|
117 |
|
118 |
|
119 {{{ Slide with code piece }}} |
|
120 |
|
121 We add the code piece to automate the test.:: |
|
122 |
|
123 |
|
124 if __name__ == '__main__': |
|
125 for line in open('testcases.txt'): |
|
126 numbers = line.split() |
|
127 x = int(numbers[0]) |
|
128 y = int(numbers[1]) |
|
129 result = int(numbers[2]) |
|
130 if gcd(x, y) != result: |
|
131 print "Failed gcd test for", x, y |
|
132 |
|
133 %% %% Pause the video do the following exercise |
|
134 %% %% For the same inputs as gcd write automated tests for LCM. |
|
135 %% %% The solution is on the screen |
|
136 |
|
137 For any program there can be innumerable test cases thus it is not |
|
138 possible to test cases. However there are many ideas to reduce the set of |
|
139 test cases by testing those cases that are more likely to show errors. |
|
140 |
|
141 Moving from testing lets talk a bit about coding style now. |
|
142 |
|
143 Apart from from being able to perform the required task, a property |
|
144 of a good program is its readability. Code is read more often than it is |
|
145 written. This is because that way other people can learn from it and extend |
|
146 and improve it. There are certain pointers for readable code that I am going to discuss. |
|
147 |
|
148 First, Naming variables. |
|
149 |
|
150 {{{ Slide with code snippet }}} |
|
151 |
|
152 Choose name that by which people will most likely guess the usage.Lets look at this |
|
153 with an example:: |
|
154 |
|
155 amount = 12.68 |
|
156 denom = 0.05 |
|
157 nCoins = round(amount/denom) |
|
158 rAmount = nCoins * denom |
|
159 |
|
160 As we can see in the example it is very easy to make what the code is doing. |
|
161 |
|
162 One can almost read it as English sentences. |
|
163 Amount is 12.68 |
|
164 Denomination is .05 |
|
165 Number of coins is round of amount by denominations. |
|
166 |
|
167 Proper naming helps so much in understanding the code. |
|
168 |
|
169 {{{ Slide with code style points }}} |
|
170 |
|
171 Also one should use. :: |
|
172 |
|
173 1.Four Space Indentation |
|
174 2.Limit to 79 characters a line, but readability should come first. |
|
175 3.Functions and methods should be separated with two blank lines. |
|
176 4.No inline comments, comments should be above the line they comment. |
|
177 5.Use Docstring to explain units of code performing specific task like |
|
178 functions. |
|
179 6.We should always have whitespace around operators and after punctuation. |
|
180 |
|
181 %% %% Pause and do the following exercise |
|
182 %% %% Give meaningful names to the variables in following |
|
183 code |
|
184 c=a/b |
|
185 |
|
186 |
|
187 This will help enormously towards making our program more readable. |
|
188 |
|
189 From coding style lets move on to handling errors and exceptions. |
|
190 |
|
191 {{{ Slide with code snippet }}} |
|
192 |
|
193 Lets try out the following piece of code:: |
|
194 |
|
195 while True print 'Hello world' |
|
196 |
|
197 {{{ Slide with Error }}} |
|
198 |
|
199 what happens when we do this on the interpreter. The interpreter |
|
200 says that this is a syntax error. Syntax error are caused when we |
|
201 do not follow the rules of the programming language. |
|
202 |
|
203 {{{ Slide with expression }}} |
|
204 |
|
205 However lets try an expression like :: |
|
206 |
|
207 1/0 |
|
208 |
|
209 {{{ Slide with Error }}} |
|
210 |
|
211 Although this expression follows the programming language rules, |
|
212 however it is not possible to express the solution of this expression. |
|
213 Thus python throws an exception called ZeroDivisionError. Exception |
|
214 is special kind of failure reported by the programming language. |
|
215 |
|
216 |
|
217 |
|
218 Lets see why and how we can use Exception in our programs. |
|
219 |
|
220 |
|
221 |
|
222 Type on your interpreter:: |
|
223 |
|
224 a = raw_input("Enter a number:") |
|
225 num = int(a) |
|
226 |
|
227 {{{ Run this code on interpreter with a character input }}} |
|
228 |
|
229 You will notice that when you run this program and give and |
|
230 non-numeric input it throws a 'ValueError' Exception. |
|
231 |
|
232 So now we can 'catch' this exception and write code to |
|
233 handle it. |
|
234 |
|
235 {{{ Slide with code snippet }}} |
|
236 |
|
237 For this we have try and except clause in python. Lets change our |
|
238 previous code slightly.:: |
|
239 |
|
240 a = raw_input("Enter a number") |
|
241 try: |
|
242 num = int(a) |
|
243 except: |
|
244 print "Wrong input ..." |
|
245 |
|
246 {{{ Run the code with character input }}} |
|
247 |
|
248 In this piece of code python tries to run the code inside the try |
|
249 block but when if it fails it executes the code block in except. |
|
250 |
|
251 In previous example we encountered a problem with running our conversion |
|
252 to integer code. We found out what caused the error and then deviced a solution |
|
253 for it this whole process is called debugging. |
|
254 |
|
255 One can understand the debugging process using the figure. |
|
256 |
|
257 In debugging process we form a hypothesis of what causes the error. |
|
258 Test if it is correct by changing the code. And refine the hypothesis |
|
259 on the basis of our result. |
|
260 |
|
261 |
|
262 |
|
263 Lets see another example of debugging. Create a file mymodule.py and |
|
264 add the following code:: |
|
265 |
|
266 def test(): |
|
267 total=1+1 |
|
268 print spam |
|
269 |
|
270 |
|
271 |
|
272 Lets now try and run this code :: |
|
273 |
|
274 import mymodule |
|
275 mymodule.test() |
|
276 |
|
277 |
|
278 {{{ Slide with idb and total being accessed }}} |
|
279 |
|
280 Interpreter gives us an error because spam is not defined |
|
281 but lets now do %debug on ipython interpreter. The prompt on the shell has changed to ipdb. This is debugger here you can access variables in that code block for example 'total'unlike the normal interpreter. |
|
282 |
|
283 %% %% Pause and do the following exercise |
|
284 %% %% Do the gcd program which takes input from user which tells |
|
285 %% %% the user wrong input if it is not valid and quits for 'q'. |
|
286 |
|
287 |
|
288 |
|
289 This brings us to the end of this tutorial on testing and debugging. |
|
290 |
|
291 |
|
292 |
|
293 |
|
294 {{{ Show the summary slide }}} |
|
295 |
|
296 In this tutorial we have learned to |
|
297 1.Create simple tests for a function. |
|
298 2.Learn to Automate tests using many predefined test cases. |
|
299 3.Good coding standards. |
|
300 4.Difference between syntax error and exception. |
|
301 5.Handling exception using try and except. |
|
302 6.Using %debug for debugging on ipython. |
|
303 |
|
304 {{{ Show the "sponsored by FOSSEE" slide }}} |
|
305 |
|
306 This tutorial was created as a part of FOSSEE project, NME ICT, MHRD India |
|
307 |
|
308 Hope you have enjoyed and found it useful. |
|
309 Thank you! |
|
310 |
|
311 |
|
312 |
|
313 |
|
314 |
|
315 |
|
316 |
|