tdd/tdd.rst
changeset 115 7455326cac40
parent 112 0b01bb6ea6b8
child 116 958e2e9f2858
equal deleted inserted replaced
114:83b3e357ed08 115:7455326cac40
   224 come a long way with respect to writing tests. But our thirst is still
   224 come a long way with respect to writing tests. But our thirst is still
   225 unquenched! We want to do more and more tests! Not just write better
   225 unquenched! We want to do more and more tests! Not just write better
   226 code but also better tests! So let us keep building upon what we have
   226 code but also better tests! So let us keep building upon what we have
   227 learnt so far.
   227 learnt so far.
   228 
   228 
   229 Let us  start writing tests  for more realistic test  cases. Generally
   229 Let us start writing tests for more realistic test cases. Generally
   230 tests  are predetermined  as said  above, if  not the  code  itself is
   230 tests are predetermined as said above, if not the software design in
   231 flawed. The predetermined tests are stored along with the test code in
   231 itself is flawed. The predetermined tests are stored along with the
   232 some  persistent way  like  in a  database,  a text  file,  a file  of
   232 test code in some persistent format like in a database, a text file, a
   233 specific format  like XML or  in other way.  Let us continue  with our
   233 file of specific format like XML or in some other way. Let us continue
   234 example of  GCD function. We  will keep all  our test cases in  a text
   234 with our example of GCD function. We will keep all our test cases in a
   235 file,  which  is  indeed   persistent.  Let  our  file  have  multiple
   235 text file, which is indeed persistent. Let us specify the format of
   236 lines. Each line in this file  corresponds to a single test case. Each
   236 the test data in our file as follows.
   237 line consists of  three coloumns: first two coloumns  are the integers
   237 
   238 for  which the GCD  has to  be computed  and the  last coloumn  is the
   238   1. The file has multiple lines of test data.
   239 expected GCD  to the  preceding two  numbers. So how  do we  write our
   239   2. Each line in this file corresponds to a single test case.
   240 tests  to use  these  test cases?  Pretty  simple, let  us review  the
   240   3. Each line consists of three comma separated coloumns:
   241 machinery required first.
   241 
   242 
   242      i. First two coloumns are the integers for which the GCD has to
   243   1. File reading: We already have learnt this in our chapters on
   243         be computed
       
   244      ii. Third coloumn is the expected GCD to the preceding two
       
   245          numbers.
       
   246 
       
   247 So how do we write our tests to use these test cases? Pretty simple, let
       
   248 us review the machinery required first.
       
   249 
       
   250   1. File reading: We already have learnt this in the modules on
   244      Basic Python.
   251      Basic Python.
   245   2. Parsing read data from file: This just involves a for loop over
   252   2. Parsing the read data from the file: This just involves a using a
   246      the data since we know that file contains lines which are
   253      **for** loop which iterates over the data line by line since we
   247      equivalent to file records and hence parse the data line by line
   254      know that the file contains each test case as a sepate line which
   248      as strings as we iterate Over it and convert it to required data
   255      are equivalent to the file records and hence parse the data line
   249      type.
   256      by line as strings as we iterate over it and convert it to the
       
   257      required data type.
   250 
   258 
   251 Since we already have all the machinery required, let us proceed writing
   259 Since we already have all the machinery required, let us proceed writing
   252 our test cases.
   260 our test cases. We do not need not make any changes to the gcd
   253 
   261 function so we will just write down the test here. Let us call our
   254 
   262 data file gcd_testcases.dat::
   255 
   263 
   256 
   264   if __name__ == '__main__':
   257 
   265       for line in open('gcd_testcases.dat'):
   258 %%%%%%%%% Much Later %%%%%%%%%%%%%%%%%
   266           values = line.split(', ')
   259 The idea of placing the tests with in the Python scripts and to
   267           a = int(values[0])
   260 execute them when the script is run as a stand-alone script works well
   268           b = int(values[1])
   261 as long as we have our code in a single Python file or the tests for
   269           g = int(values[2])
   262 each script can be run separately. But in a more realistic software
   270 
   263 development scenario, often this is not the case. The code is spread
   271           tc = gcd(a, b)
   264 around multiple Python scripts, each Python script also being called
   272           if tc != g:
   265 as a Python module, and across several Python packages. In such a
   273               print "Test failed for the case a=%d and b=%d. Expected %d. Obtained %d instead." % (a, b, g, tc)
   266 scenario we may want to do more.
   274               exit(1)
       
   275 
       
   276       print "All tests passed!"
       
   277 
       
   278 When we execute the gcd.py script again we will notice that all the
       
   279 tests passed.
       
   280 
       
   281 Running at the **nose**
       
   282 =======================
       
   283 
       
   284 Not too far ahead we go we will start running at the nose saying of
       
   285 Python developers saying that this is not sufficient to write
       
   286 complicated tests in an efficient manner and writing tests for the
       
   287 programs are so important that Python should provide a tool for
       
   288 managing large tests. To further explain, the idea of placing the
       
   289 tests with in the Python scripts and to execute them when the script
       
   290 is run as a stand-alone script works well as long as we have our code
       
   291 in a single Python file or as long as the tests for each script can be
       
   292 run separately. But in a more realistic software development scenario,
       
   293 often this is not the case. The code is spread around multiple Python
       
   294 scripts, each script also called as a Python module, and also across
       
   295 several Python packages.
       
   296 
       
   297 In such a scenario what we would like to do is to create a separate
       
   298 directory for holding these test. The structure of this directory is
       
   299 the exact replica of the Python package hierarchy of our software to
       
   300 be tested. This structure is especially useful because of the fact
       
   301 that we have a one to one correspondence to our code and to its test.
       
   302 Hence it is easy for us to navigate through the tests as we maintain
       
   303 the existing tests and to add new tests as the code evolves. We have a
       
   304 collection of tests in the specified structure. Any collection of
       
   305 tests is called as the test suite for the *software package*. Hence we
       
   306 shall call this directory of tests as our test suite.
       
   307 
       
   308 Fine we have all these, but how do we make our tests aware that they
       
   309 are the tests for such and such a Python module or code and when
       
   310 executed must test that corresponding code? To make the lives of
       
   311 Python developers and testers easy Python provides a very handy tool
       
   312 called as **nose**. The name should have been pretty evident from the
       
   313 heading of this section! So in the rest of this module let us discuss
       
   314 how to use **nose** to write, maintain and extend our tests as the
       
   315 code evolves.