|
1 ====================================== |
|
2 Lab Workbook - Test Driven Development |
|
3 ====================================== |
|
4 |
|
5 The notation that follows every question denotes the level on the |
|
6 Revised Bloom's Taxonomy. |
|
7 |
|
8 Lab - 1 |
|
9 ======= |
|
10 |
|
11 1. Write a stub function for calculating the LCM of two numbers. |
|
12 - U-level |
|
13 2. Write the tests for the LCM function, place the tests in if |
|
14 __name__ == '__main__': part of the Python file. Demonstrate that |
|
15 the tests fail. - U-level |
|
16 3. Implement the code for the LCM function, using the gcd function |
|
17 provided in the examples in the chapter. Demonstrate the tests |
|
18 pass. (For the algorithm refer to Wikipedia - [0]) - Ap-level |
|
19 4. Alternatively, build a set of test cases, preferably a large |
|
20 number of cases, place it in a text file and use these test cases |
|
21 to test your LCM function. Demonstrate that tests still continue |
|
22 to pass. - U-level |
|
23 |
|
24 [0] - http://en.wikipedia.org/wiki/Least_common_multiple#Reduction_by_the_greatest_common_divisor |
|
25 |
|
26 Lab - 2 |
|
27 ======= |
|
28 |
|
29 1. Write the stub function, followed by the tests(demonstrating the |
|
30 failed tests), in turn followed by the code(demonstrating the |
|
31 passing tests) to calculate the number of days between two |
|
32 dates. Name your function num_of_days(). The function should take |
|
33 two arguments, both being tuples. Each tuple represents the date |
|
34 in the format of (dd, mm, yyyy) where dd, mm and yyyy are |
|
35 integers. - Ap-level |
|
36 |
|
37 2. Rewrite the num_of_days() function to take the start date as an |
|
38 optional argument. If the start date is not specified calculate |
|
39 the number of days between the only specified date since Unix |
|
40 epoch. Prior to manipulating the code to do this, make sure you |
|
41 change the tests, make them fail and then refactor the code. |
|
42 - Ap-level |
|
43 |
|
44 |
|
45 Lab -3 |
|
46 ====== |
|
47 |
|
48 1. Move the tests that were written to GCD function in the examples |
|
49 of this chapter to a separate function called test_gcd(). Do the |
|
50 same for LCM function and num_of_days() function. Make sure when |
|
51 the respective Python files are executed as stand alone scripts |
|
52 these tests executed. - U-level |
|
53 2. Put all these files in a single directory called utils and run |
|
54 the nosetests command. Make a report of the results. - U-level |
|
55 3. Write doctests to each of the above functions. Demonstrate and |
|
56 report the results as executed by running the doctests using |
|
57 doctest.testmod() function and using nosetests command. -Ap-level |
|
58 |
|
59 Lab - 4 |
|
60 ======= |
|
61 |
|
62 1. Consider the following use case: We are given a large list of |
|
63 items called *data* where each item is a again a list with three |
|
64 values: username, which is a string; status of the user which |
|
65 can be one of the following three strings 'new', 'valid' or |
|
66 'invalid'; and the last login time which is a datetime Python |
|
67 object. Write a function called **query** that takes a filter |
|
68 dictionary as a parameter and returns the result of the items in |
|
69 the *data* list. They keys of the dictionary can be 'user', |
|
70 'status' and 'logtime' and their corresponding values can be any |
|
71 of the valid values for the corresponding key. Example filter |
|
72 dictionary:: |
|
73 |
|
74 filter = { |
|
75 'user': 'john' |
|
76 'status': 'new' |
|
77 } |
|
78 |
|
79 Place your function in a file called query.py. Before writing the |
|
80 actual function, follow the test driven development |
|
81 approach. First write a stub, fail the tests and then write the |
|
82 code and make sure the tests pass. Specifically use unittest |
|
83 framework to test this function. Place your tests in a file |
|
84 called test_query.py |
|
85 |
|
86 A developer wrote a small utility function in a file named |
|
87 user_utils.py which uses your **query** function which looks as |
|
88 follows:: |
|
89 |
|
90 def login_util(user=None): |
|
91 """Takes a user name and returns his last login time if the |
|
92 user is a valid user, else return None. If the user is |
|
93 'host' it returns the last login time of all the users. |
|
94 """ |
|
95 |
|
96 filter_dict = { |
|
97 'user': user |
|
98 'status': 'active' |
|
99 } |
|
100 |
|
101 if user == 'host': |
|
102 filter_dict['status'] + ['new', 'invalid'] |
|
103 |
|
104 return query(filter_dict) |
|
105 |
|
106 Unfortunately the developer did not provide us with the test |
|
107 cases. We wrote the following test cases for you to only discover |
|
108 that the function miserably fails. |
|
109 |
|
110 The tests were placed in a file called test_user_utils.py and we |
|
111 have used the unittest framework:: |
|
112 |
|
113 import query |
|
114 import user_utils |
|
115 import unittest |
|
116 |
|
117 class TestUserUtils(unittest.TestCase): |
|
118 |
|
119 def setUp(self): |
|
120 """Boiler plate method to provide common data to all |
|
121 the test methods. |
|
122 """ |
|
123 self.test_names = ['Alex', 'Guido', 'Thomas', 'host', |
|
124 'Tom', 'James'] |
|
125 self.data_len = len(query.data) |
|
126 |
|
127 def test_login_utils(self): |
|
128 """Tests for the login_utils function. |
|
129 """ |
|
130 |
|
131 for name in self.test_names: |
|
132 if name == 'host': |
|
133 assertEqual(len(user_utils.login_utils(name)), self.data_len) |
|
134 else: |
|
135 assertLess(len(user_utils.login_utils(name)), self.data_len) |
|
136 |
|
137 def tearDown(self): |
|
138 """Boiler plate method to clean up all the data created |
|
139 for tests. |
|
140 """ |
|
141 |
|
142 del self.test_names |
|
143 del self.data_len |
|
144 |
|
145 Fix the bug, run the tests to make sure the function passes the |
|
146 tests and if possible refactor the code with a better approach. - An-level |