tdd/lab-workbook.rst
author Puneeth Chaganti <punchagan@fossee.in>
Mon, 31 Jan 2011 17:19:51 +0530
changeset 154 148520862e53
parent 130 e5d183dce985
permissions -rw-r--r--
vcs: Minor fixes to handout. 1. Made madhu's commit shorter to fit in one line. 2. Change Author details to have just the Name. 3. Change some punctuation.

======================================
Lab Workbook - Test Driven Development
======================================

The notation that follows every question denotes the level on the
Revised Bloom's Taxonomy.

Lab - 1
=======

  1. Write a stub function for calculating the LCM of two numbers.
                                                            - U-level
  2. Write the tests for the LCM function, place the tests in if
     __name__ == '__main__': part of the Python file. Demonstrate that
     the tests fail.                                        - U-level
  3. Implement the code for the LCM function, using the gcd function
     provided in the examples in the chapter. Demonstrate the tests
     pass. (For the algorithm refer to Wikipedia - [0])     - Ap-level
  4. Alternatively, build a set of test cases, preferably a large
     number of cases, place it in a text file and use these test cases
     to test your LCM function. Demonstrate that tests still continue
     to pass.                                               - U-level

[0] - http://en.wikipedia.org/wiki/Least_common_multiple#Reduction_by_the_greatest_common_divisor

Lab - 2
=======

  1. Write the stub function, followed by the tests(demonstrating the
     failed tests), in turn followed by the code(demonstrating the
     passing tests) to calculate the number of days between two
     dates. Name your function num_of_days(). The function should take
     two arguments, both being tuples. Each tuple represents the date
     in the format of (dd, mm, yyyy) where dd, mm and yyyy are
     integers.                                              - Ap-level

  2. Rewrite the num_of_days() function to take the start date as an
     optional argument. If the start date is not specified calculate
     the number of days between the only specified date since Unix
     epoch. Prior to manipulating the code to do this, make sure you
     change the tests, make them fail and then refactor the code.
                                                            - Ap-level


Lab -3
======

  1. Move the tests that were written to GCD function in the examples
     of this chapter to a separate function called test_gcd(). Do the
     same for LCM function and num_of_days() function. Make sure when
     the respective Python files are executed as stand alone scripts
     these tests executed.                                  - U-level
  2. Put all these files in a single directory called utils and run
     the nosetests command. Make a report of the results.   - U-level
  3. Write doctests to each of the above functions. Demonstrate and
     report the results as executed by running the doctests using
     doctest.testmod() function and using nosetests command. -Ap-level

Lab - 4
=======

  1. Consider the following use case: We are given a large list of
     items called *data* where each item is a again a list with three
     values: username, which is a string; status of the user which
     can be one of the following three strings 'new', 'valid' or
     'invalid'; and the last login time which is a datetime Python
     object.  Write a function called **query** that takes a filter
     dictionary as a parameter and returns the result of the items in
     the *data* list. They keys of the dictionary can be 'user',
     'status' and 'logtime' and their corresponding values can be any
     of the valid values for the corresponding key. Example filter
     dictionary::

       filter = {
           'user': 'john'
           'status': 'new'
           }

     Place your function in a file called query.py. Before writing the
     actual function, follow the test driven development
     approach. First write a stub, fail the tests and then write the
     code and make sure the tests pass. Specifically use unittest
     framework to test this function. Place your tests in a file
     called test_query.py

     A developer wrote a small utility function in a file named
     user_utils.py which uses your **query** function which looks as
     follows::

       def login_util(user=None):
           """Takes a user name and returns his last login time if the
           user is a valid user, else return None. If the user is
           'host' it returns the last login time of all the users.
           """

           filter_dict = {
               'user': user
               'status': 'active'
               }

           if user == 'host':
               filter_dict['status'] + ['new', 'invalid']

           return query(filter_dict)

     Unfortunately the developer did not provide us with the test
     cases. We wrote the following test cases for you to only discover
     that the function miserably fails. 

     The tests were placed in a file called test_user_utils.py and we
     have used the unittest framework::

       import query
       import user_utils
       import unittest

       class TestUserUtils(unittest.TestCase):
        
           def setUp(self):
               """Boiler plate method to provide common data to all
               the test methods.
               """
               self.test_names = ['Alex', 'Guido', 'Thomas', 'host',
                   'Tom', 'James']
               self.data_len = len(query.data)

           def test_login_utils(self):
               """Tests for the login_utils function.
               """

               for name in self.test_names:
                   if name == 'host':
                       assertEqual(len(user_utils.login_utils(name)), self.data_len)
                   else:
                       assertLess(len(user_utils.login_utils(name)), self.data_len)

           def tearDown(self):
               """Boiler plate method to clean up all the data created
               for tests.
               """

               del self.test_names
               del self.data_len

     Fix the bug, run the tests to make sure the function passes the
     tests and if possible refactor the code with a better approach. - An-level