tdd/tdd.rst
changeset 117 fab0281a992f
parent 116 958e2e9f2858
child 120 7428e411bd7a
equal deleted inserted replaced
116:958e2e9f2858 117:fab0281a992f
   212   def gcd(a, b):
   212   def gcd(a, b):
   213       if b == 0:
   213       if b == 0:
   214           return a
   214           return a
   215       return gcd(b, a%b)
   215       return gcd(b, a%b)
   216 
   216 
   217 Much shorter and sweeter! And it passes all the tests!
   217 Much shorter and sweeter! And it passes all the tests! But there is
   218 
   218 one small problem yet. For the users of this function there is no way
       
   219 to determine how to use it, how many parameters it takes what it
       
   220 returns among other things. And same as well for those who read the
       
   221 code. So this function is not a very well written piece of code since
       
   222 it lacks documentation. So to make this function mode readable let us
       
   223 add the docstring for this function. Rewriting the function with the
       
   224 docstring looks like this::
       
   225 
       
   226   def gcd(a, b):
       
   227       """Returns the Greatest Common Divisor of the two integers
       
   228       passed as arguments.
       
   229 
       
   230       Args:
       
   231         a: an integer
       
   232         b: another integer
       
   233 
       
   234       Returns: Greatest Common Divisor of a and b
       
   235       """
       
   236       if b == 0:
       
   237           return a
       
   238       return gcd(b, a%b)
       
   239 
       
   240 Now we have refactored our code enough to make it well written piece
       
   241 of code. Let us move on.
   219 
   242 
   220 More realistic "Tests"
   243 More realistic "Tests"
   221 ======================
   244 ======================
   222 
       
   223 
   245 
   224 Now we have successfully completed writing our first test, writing the
   246 Now we have successfully completed writing our first test, writing the
   225 relevant code and ensured the tests passed. We also refactored our
   247 relevant code and ensured the tests passed. We also refactored our
   226 code to perform better. With the knowledge of all these and some
   248 code to perform better. With the knowledge of all these and some
   227 concepts and semantics like __main__ magic names we learnt we have
   249 concepts and semantics like __main__ magic names we learnt we have
   280       print "All tests passed!"
   302       print "All tests passed!"
   281 
   303 
   282 When we execute the gcd.py script again we will notice that all the
   304 When we execute the gcd.py script again we will notice that all the
   283 tests passed.
   305 tests passed.
   284 
   306 
   285 Running at the **nose**
   307 Python Testing Framework
   286 =======================
   308 ========================
   287 
   309 
   288 Not too far ahead we go we will start running at the nose saying of
   310 Python provides two ways to test the code we have written. One of them
   289 Python developers saying that this is not sufficient to write
   311 is the unittest framework and the the other is the doctest module.
   290 complicated tests in an efficient manner and writing tests for the
   312 
   291 programs are so important that Python should provide a tool for
   313 doctest
   292 managing large tests. To further explain, the idea of placing the
   314 ~~~~~~~
   293 tests with in the Python scripts and to execute them when the script
   315 
   294 is run as a stand-alone script works well as long as we have our code
   316 To start with let us discuss the doctest module. As we have already
   295 in a single Python file or as long as the tests for each script can be
   317 discussed a well written piece of code must always be accompanied by
   296 run separately. But in a more realistic software development scenario,
   318 its documentation. For a function or a module we document them in their
       
   319 respective docstrings. In addition to this, we can also place the
       
   320 samples of using these functions or modules in the Python interactive
       
   321 interpreter in the docstrings. When we run the doctest module it picks
       
   322 up all such interactive session samples, executes them and determines
       
   323 if the documented piece of code runs as it is documented. Let us see
       
   324 how to write doctests for our gcd function::
       
   325 
       
   326   def gcd(a, b):
       
   327       """Returns the Greatest Common Divisor of the two integers
       
   328       passed as arguments.
       
   329 
       
   330       Args:
       
   331         a: an integer
       
   332         b: another integer
       
   333 
       
   334       Returns: Greatest Common Divisor of a and b
       
   335 
       
   336       >>> gcd(48, 64)
       
   337       16
       
   338       >>> gcd(44, 19)
       
   339       1
       
   340       """
       
   341       if b == 0:
       
   342           return a
       
   343       return gcd(b, a%b)
       
   344 
       
   345 This is all a doctest is. To explain it in more simple terms tests
       
   346 which are written as part of the docstrings are called as
       
   347 doctests. Now how do we use our doctest module to execute this
       
   348 tests. That is fairly straight forward as well. All we need to do is
       
   349 tell the doctest module to execute. Let us place this piece of code at
       
   350 the same place where we placed our tests earlier. So putting all these
       
   351 together we have our gcd.py module which looks as follows::
       
   352 
       
   353   def gcd(a, b):
       
   354       """Returns the Greatest Common Divisor of the two integers
       
   355       passed as arguments.
       
   356 
       
   357       Args:
       
   358         a: an integer
       
   359         b: another integer
       
   360 
       
   361       Returns: Greatest Common Divisor of a and b
       
   362 
       
   363       >>> gcd(48, 64)
       
   364       16
       
   365       >>> gcd(44, 19)
       
   366       1
       
   367       """
       
   368       if b == 0:
       
   369           return a
       
   370       return gcd(b, a%b)
       
   371 
       
   372   if __name__ == "__main__":
       
   373       import doctest
       
   374       doctest.testmod()
       
   375 
       
   376 All we need to do is import the doctest module that is part of the
       
   377 Python's standard library. Call the testmod() function in this
       
   378 module. This function automatically checks for all the docstrings that
       
   379 have sample sessions from the interactive interpreter, if they exist
       
   380 it executes them and compares the output with the results as specified
       
   381 in the sample sessions. It complains if the results don't match as
       
   382 documented. When we execute this script as a stand-alone script we
       
   383 will get back the prompt with no messages which means all the tests
       
   384 passed::
       
   385 
       
   386   madhu@madhu:~$ python gcd.py
       
   387   madhu@madhu:~$ 
       
   388 
       
   389 If we further want to get a more detailed report of the tests that
       
   390 were executed we can run python with -v as the command line option
       
   391 to the script::
       
   392 
       
   393   madhu@madhu:~$ python gcd.py -v
       
   394   Trying:
       
   395       gcd(48, 64)
       
   396   Expecting:
       
   397     16
       
   398   ok
       
   399   Trying:
       
   400       gcd(44, 19)
       
   401   Expecting:
       
   402       1
       
   403   ok
       
   404   1 items had no tests:
       
   405       __main__
       
   406   1 items passed all tests:
       
   407      2 tests in __main__.gcd
       
   408   2 tests in 2 items.
       
   409   2 passed and 0 failed.
       
   410   Test passed.
       
   411 
       
   412 
       
   413 **Note:** We can have the sample sessions as test cases as long as the
       
   414 outputs of the test cases do not contain any blank lines. In such
       
   415 cases we may have to use the exact string *<BLANKLINE>*
       
   416 
       
   417 For the sake of illustrating a failing test case, let us assume that
       
   418 we made a small mistake in our code. Instead of returning **a** when b
       
   419 = 0 we typed it as return b when b = 0. So all the gcds returned will
       
   420 have the value of 0 in such a piece of code. The code looks as
       
   421 follows::
       
   422 
       
   423   def gcd(a, b):
       
   424       """Returns the Greatest Common Divisor of the two integers
       
   425       passed as arguments.
       
   426 
       
   427       Args:
       
   428         a: an integer
       
   429         b: another integer
       
   430 
       
   431       Returns: Greatest Common Divisor of a and b
       
   432 
       
   433       >>> gcd(48, 64)
       
   434       16
       
   435       >>> gcd(44, 19)
       
   436       1
       
   437       """
       
   438       if b == 0:
       
   439           return a
       
   440       return gcd(b, a%b)
       
   441 
       
   442 Executing this code snippet without -v option to the script::
       
   443 
       
   444   madhu@madhu:~$ python gcd.py
       
   445   **********************************************************************
       
   446   File "gcd.py", line 11, in __main__.gcd
       
   447   Failed example:
       
   448       gcd(48, 64)
       
   449   Expected:
       
   450       16
       
   451   Got:
       
   452       0
       
   453   **********************************************************************
       
   454   File "gcd.py", line 13, in __main__.gcd
       
   455   Failed example:
       
   456       gcd(44, 19)
       
   457   Expected:
       
   458       1
       
   459   Got:
       
   460       0
       
   461   **********************************************************************
       
   462   1 items had failures:
       
   463      2 of   2 in __main__.gcd
       
   464   ***Test Failed*** 2 failures.
       
   465 
       
   466 The output clearly complains that there were exactly two test cases
       
   467 that failed. If we want a more verbose report we can pass -v option to
       
   468 the script. This is pretty much about the doctest module in
       
   469 Python. doctest is extremely useful when we want to test each Python
       
   470 function or module individually. For more information about the
       
   471 doctest module refer to the Python library reference on doctest[0].
       
   472 
       
   473 unittest framework
       
   474 ~~~~~~~~~~~~~~~~~~
       
   475 
       
   476 Not too far ahead we go we, we will start complaining that the doctest
       
   477 is not sufficient to write complicated tests especially when we want
       
   478 to automate our tests, write tests that need to test for more
       
   479 convoluted code pieces. For such scenarios Python provides a unittest
       
   480 framework.  unittest framework provides methods to efficiently
       
   481 automate tests, setup and teardown functionalities which helps to
       
   482 setup the initializing code and data for executing the specific tests
       
   483 and cleanly shutting them down once the tests are executed and ways to
       
   484 aggregate tests into collections and better way of reporting the
       
   485 tests.
       
   486 
       
   487 Let us continue testing our gcd function in the Python module named
       
   488 gcd.py. To get ourselves started, the unittest framework expects us to
       
   489 subclass TestCase class in unittest module and place all our test code
       
   490 as methods of this class. We will begin the name of the test method
       
   491 with **test_** so that the test runner knows which methods are to be
       
   492 executed as tests. We will use the test cases supplied by
       
   493 gcd_testcases.dat. Lastly, to illustrate the way to test Python code
       
   494 as a module let create a new file called test_gcd.py following the
       
   495 same convention used to name the test methods. We will place our test
       
   496 code within test_gcd.py module. Our test code looks like this::
       
   497   
       
   498   import gcd
       
   499   import unittest
       
   500 
       
   501   class TestGcdFunction(unittest.TestCase):
       
   502 
       
   503       def setUp(self):
       
   504           self.test_file = open('gcd_testcases.dat')
       
   505           self.test_cases = []
       
   506           for line in self.test_file:
       
   507               values = line.split(', ')
       
   508               a = int(values[0])
       
   509               b = int(values[1])
       
   510               g = int(values[2])
       
   511 
       
   512               self.test_cases.append([a, b, g])
       
   513 
       
   514       def test_gcd(self):
       
   515           for case in self.test_cases:
       
   516               a = case[0]
       
   517               b = case[1]
       
   518               g = case[2]
       
   519               self.assertEqual(gcd.gcd(a, b), g)
       
   520 
       
   521       def tearDown(self):
       
   522           self.test_file.close()
       
   523           del self.test_cases
       
   524 
       
   525   if __name__ == '__main__':
       
   526       unittest.main()
       
   527 
       
   528 
       
   529 
       
   530  Since we don't want to read this file into memory each time we run a
       
   531 separate test method, we will read all the data in the file into
       
   532 Python lists in the setUp function and in the tearDown function of the
       
   533 
       
   534 
       
   535 
       
   536 
       
   537 To further explain the idea, the idea of placing tests with in the
       
   538 Python scripts and to execute them when the script is run as a
       
   539 stand-alone script works well as long as we have our code in a single
       
   540 Python file or as long as the tests for each script can be run
       
   541 separately. But in a more realistic software development scenario,
   297 often this is not the case. The code is spread around multiple Python
   542 often this is not the case. The code is spread around multiple Python
   298 scripts, each script also called as a Python module, and also across
   543 scripts, each script, also called as a Python module, and may be even
   299 several Python packages.
   544 across several Python packages.
   300 
   545 
   301 In such a scenario what we would like to do is to create a separate
   546 In such a scenario what we would like to do is to create a separate
   302 directory for holding these test. The structure of this directory is
   547 directory for holding these test. The structure of this directory is
   303 the exact replica of the Python package hierarchy of our software to
   548 the exact replica of the Python package hierarchy of our software to
   304 be tested. This structure is especially useful because of the fact
   549 be tested. This structure is especially useful because of the fact
   315 Python developers and testers easy Python provides a very handy tool
   560 Python developers and testers easy Python provides a very handy tool
   316 called as **nose**. The name should have been pretty evident from the
   561 called as **nose**. The name should have been pretty evident from the
   317 heading of this section! So in the rest of this module let us discuss
   562 heading of this section! So in the rest of this module let us discuss
   318 how to use **nose** to write, maintain and extend our tests as the
   563 how to use **nose** to write, maintain and extend our tests as the
   319 code evolves.
   564 code evolves.
       
   565 
       
   566 Running at the **nose**
       
   567 =======================
       
   568 
       
   569 
       
   570 [0] - http://docs.python.org/library/doctest.html