tdd/tdd.rst
author Madhusudan.C.S <madhusudancs@gmail.com>
Tue, 31 Aug 2010 20:15:06 +0530
changeset 115 7455326cac40
parent 112 0b01bb6ea6b8
child 116 958e2e9f2858
permissions -rw-r--r--
Completed the section on realistic test scenarios and introductory paragraphs on nose.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
89
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
     1
Fundamentals
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
     2
============
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
     3
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
     4
Test Driven Development, abbreviated as TDD is a method of software
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
     5
development which banks on the idea of writing test cases that fail for the
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
     6
code that doesn't even exist yet. The actual code is written later to pass
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
     7
the test and then refactored.
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
     8
109
0afd25eadf41 Add a section on real life tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 89
diff changeset
     9
First "Test"
0afd25eadf41 Add a section on real life tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 89
diff changeset
    10
============
89
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    11
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    12
Writing a test is simple. Writing a failing test? It is much more simple.
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    13
Let us consider a very simple program which returns the Greatest Common
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    14
Divisor (GCD) of two numbers. Since the test cases for the code is written
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    15
prior to the code itself, it is necessary to have a clear idea of the code
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    16
units that our program will contain. Let us attempt to clearly define the
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    17
code units in our case of a GCD program. Let our program contain one and
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    18
only one function called gcd() which takes in two arguments as parameters.
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    19
These arguments are the numbers for which GCD must be computed. The gcd()
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    20
function returns a single value which is the GCD of the two arguments
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    21
passed. So if we want to find out GCD of 44, 23, I will call my code unit
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    22
as c = gcd(44, 23) where c will contain the GCD of those two numbers.
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    23
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    24
Now we have defined our code units, how will we write tests? Before writing
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    25
the test, a very fundamental question arises in our minds. How do tests
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    26
look like? So let us answer this question first. Tests are nothing but a
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    27
series of assertions which are either True or False depending on the
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    28
expected behaviour of the code. We tell our tests whether our code unit
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    29
asserts True or asserts False based on the expected behaviour of the code
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    30
units. If we happen to run the tests now we are sure to get errors. Oh! But
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    31
why? We don't even have the function gcd to call. The test code doesn't
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    32
even compile! So what should we do now? So the idea is to first write the
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    33
stubs for the code units before we start writing tests. This is necessary
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    34
for two reasons. Firstly, by writing the stubs for the code units we will
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    35
be able to correctly decide and fix on to the code units that we have
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    36
planned to include in our program. We have a clear cut idea as to how our
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    37
program is structured, how the tests must be written among other
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    38
things. Secondly, the tests must at least compile and then fail! If the
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    39
tests don't even compile, that doesn't mean the tests failed. It means
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    40
it was a failure on the programmer's part. Let us define our stub::
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    41
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    42
  def gcd(a, b):
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    43
      pass
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    44
110
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    45
This stub does nothing other than defining a new function called gcd
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    46
which takes two parameters a and b for which the GCD must be
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    47
calculated. The body of the function just contains Python's **pass**
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    48
statement which means it does nothing, i.e. empty. We have our stub
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    49
ready. One important thing we need to keep in mind when we adopt TDD
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    50
methodology is that we need to have a clear set of results defined for
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    51
our code units. To put it more clearly, for every given set of inputs
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    52
as test case we must have, before hand, the exact outputs that are
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    53
expected for those input test cases. If we don't have that we have
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    54
failed in the first step of the TDD methodology itself. We must never
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    55
run looking for outputs for our test cases after we have the code
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    56
ready or even while writing tests. The expected outputs/behaviour must
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    57
be in our hands before we start writing tests. Therefore let us define
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    58
our test cases and the expected output for those inputs. Let one of
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    59
our test cases be 48 and 64 as *a* and *b* respectively. For this test
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    60
case we know that the GCD is 16. So that is the expected output. Let
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    61
our second test case be 44 and 19 as *a* and *b* respectively. We know
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    62
that their GCD is 1 by simple paper and pen calculation.
89
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    63
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    64
Now we know what a test is? What are the ingredients required to write
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    65
tests? So what else should we wait for? Let us write our first test!::
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    66
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    67
  tc1 = gcd(48, 64)
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    68
  if tc1 != 16:
110
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    69
      print "Test failed for the case a=48 and b=64. Expected 16. Obtained %d instead." % tc1
89
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    70
      exit(1)
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    71
  
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    72
  tc2 = gcd(44, 19)
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    73
  if tc2 != 1:
110
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    74
      print "Test failed for the case a=44 and b=19. Expected 1. Obtained %d instead." % tc2
89
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    75
      exit(1)
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    76
449760bc4089 Adding initial fundamentals and basic test content for TDD module.
Madhusudan.C.S <madhusudancs@gmail.com>
parents:
diff changeset
    77
  print "All tests passed!"
109
0afd25eadf41 Add a section on real life tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 89
diff changeset
    78
110
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    79
Let us put all these in a file and call this file **gcd.py**::
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    80
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    81
  def gcd(a, b):
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    82
      pass
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    83
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    84
  if __name__ == '__main__':
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    85
      tc1 = gcd(48, 64)
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    86
      if tc1 != 16:
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    87
          print "Test failed for the case a=48 and b=64. Expected 16. Obtained %d instead." % tc1
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    88
          exit(1)
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    89
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    90
      tc2 = gcd(44, 19)
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    91
      if tc2 != 1:
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    92
          print "Test failed for the case a=44 and b=19. Expected 1. Obtained %d instead." % tc2
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    93
          exit(1)
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    94
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    95
      print "All tests passed!"
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    96
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    97
Note that we have introduced a new semantic which uses two new magic names
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    98
in Python *__name__* and *__main__*. This is a very common idiom used in
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
    99
Python. Every Python code in a file can be run in two ways: Either as an
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   100
independent stand-alone script or as a Python module which can be imported
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   101
by other Python scripts or modules. When the idiom::
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   102
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   103
  if __name__ == '__main__':
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   104
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   105
is used, the code within this if block is executed first when we run the
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   106
Python file as a stand-alone script. In other words, when we run this
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   107
python file as a stand-alone script the control of the program first starts
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   108
from the code that is within this if block from which the control is
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   109
transferred to other parts of the program or to other modules from
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   110
here. This comes as an extremely handy feature especially when we want to
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   111
test our modules individually. Now let us run our code as a stand-alone
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   112
script.::
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   113
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   114
  madhu@madhu:~/Desktop$ python gcd.py
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   115
  Traceback (most recent call last):
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   116
    File "gcd.py", line 7, in <module> print "Test failed for the case a=48 and b=64. Expected 16. Obtained %d instead." % tc1
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   117
  TypeError: %d format: a number is required, not NoneType
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   118
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   119
Now we have our tests, the test cases and the code unit stub at
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   120
hand. We also have the failing test. So we know for sure that we have
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   121
cleared the first check point of TDD where the tests have failed. The
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   122
failing tests also give a green signal for us to go ahead to our next
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   123
check point i.e. to write the actual code in our code unit and make
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   124
the test pass. So let us write the code for the gcd function by
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   125
removing the **pass** control statement which had just created a gcd
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   126
function stub for us.
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   127
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   128
Most of us have learnt in high school math classes that the best and
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   129
the easiest known algorithm to compute the gcd of two numbers was
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   130
given to us 2300 years ago by a greek mathematician named Euclid. So
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   131
let us use the Euclid's algorithm to compute the gcd of two numbers a
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   132
and b::
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   133
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   134
  def gcd(a, b):
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   135
      if a == 0:
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   136
          return b
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   137
      while b != 0:
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   138
          if a > b:
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   139
              a = a - b
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   140
          else:
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   141
              b = b - a
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   142
      return a
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   143
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   144
**Note**: If you are unaware of Euclidean algorithm to compute the gcd
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   145
of two numbers please refer to it on wikipedia. It has a very detailed
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   146
explanation of the algorithm and its proof of validity among other
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   147
things.
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   148
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   149
Now let us run our script which already has the tests written in it
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   150
and see what happens::
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   151
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   152
  madhu@madhu:/media/python/sttp/tdd$ python gcd.py
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   153
  All tests passed!
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   154
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   155
Success! We managed to pass all the tests. But wasn't that code simple
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   156
enough? Indeed it was. If you take a closer look at the code you will
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   157
soon realize that the chain of subtraction operations can be replaced
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   158
by a modulo operation i.e. taking remainders of the division between
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   159
the two numbers since they are equivalent operations. Also modulo
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   160
operation is far better than chain of subtractions because you will
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   161
reduce much faster using modulo operation than the subtraction. For
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   162
example if let us take 25, 5 as a and b in our example. If we write
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   163
down the steps of the algorithm written above we have the following:
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   164
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   165
Step 1: a = 25 b = 5: Since both a and b are not 0 and b is greater
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   166
than a: b = 25 - 5 = 20
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   167
Step 2: Since b is still not 0 and b is greater than a: b = 20 - 5 =
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   168
15
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   169
Step 3: Since b is still not 0 and b is greater than a: b = 15 - 5 =
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   170
10
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   171
Step 4: Since b is still not 0 and b is greater than a: b = 10 - 5 = 5
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   172
Step 5: Since b is still not 0 and b is equal to a: b = 5 - 5 = 0
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   173
Step 6: Since b is 0 the gcd is a = 5 which is returned
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   174
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   175
If we adopt the modulo operation instead of subtraction and follow the
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   176
steps:
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   177
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   178
Step 1: a = 25 b = 5: Since both a and b are not 0 and b is greater
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   179
than a: b = 25 % 5 = 0
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   180
Step 2: Since b is 0 the gcd is a = 5 which is returned
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   181
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   182
Wow! That was overwhelmingly lesser number of steps! So now we are
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   183
convinced that if we replace the subtraction operation with the modulo
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   184
operation our code performs much better. But if we think carefully we
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   185
know that the modulo of a and b is less than b irrespective of how
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   186
large the value of a is, including the case where a is already less
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   187
than b. So we can eliminate that extra conditional **if** statement by
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   188
just swapping the result of the modulo operation to the position of b
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   189
and b to the position of a. This ensures that a is always greater than
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   190
b and if not the swapping combined with modulo operation takes care of
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   191
it. To exemplify it, if a = 5 and b = 25 then by swapping and
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   192
performing modulo we have a = b = 25 and b = a % b = 5 % 25 = 5 and
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   193
hence we proceed. So let us replace our original code with this new
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   194
improved code we have come up with simple observations::
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   195
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   196
  def gcd(a, b):
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   197
      while b != 0:
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   198
          a, b = b, a % b
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   199
      return a
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   200
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   201
Executing our script again we will see that all the tests pass. One
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   202
final improvement we can think of which is not necessary in terms of
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   203
efficiency but is certainly good to do keeping in mind the readability
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   204
is that we can use the concept of recursion for the same
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   205
algorithm. Without going into much detail this is how the code looks
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   206
if we use a recursive approach::
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   207
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   208
  def gcd(a, b):
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   209
      if b == 0:
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   210
          return a
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   211
      return gcd(b, a%b)
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   212
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   213
Much shorter and sweeter! And it passes all the tests!
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   214
4e7b98636b58 Improved the initial Introduction on tests content.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 109
diff changeset
   215
109
0afd25eadf41 Add a section on real life tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 89
diff changeset
   216
More realistic "Tests"
0afd25eadf41 Add a section on real life tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 89
diff changeset
   217
======================
0afd25eadf41 Add a section on real life tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 89
diff changeset
   218
112
0b01bb6ea6b8 Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 110
diff changeset
   219
0b01bb6ea6b8 Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 110
diff changeset
   220
Now we have successfully completed writing our first test, writing the
0b01bb6ea6b8 Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 110
diff changeset
   221
relevant code and ensured the tests passed. We also refactored our
0b01bb6ea6b8 Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 110
diff changeset
   222
code to perform better. With the knowledge of all these and some
0b01bb6ea6b8 Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 110
diff changeset
   223
concepts and semantics like __main__ magic names we learnt we have
0b01bb6ea6b8 Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 110
diff changeset
   224
come a long way with respect to writing tests. But our thirst is still
0b01bb6ea6b8 Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 110
diff changeset
   225
unquenched! We want to do more and more tests! Not just write better
0b01bb6ea6b8 Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 110
diff changeset
   226
code but also better tests! So let us keep building upon what we have
0b01bb6ea6b8 Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 110
diff changeset
   227
learnt so far.
0b01bb6ea6b8 Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 110
diff changeset
   228
115
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   229
Let us start writing tests for more realistic test cases. Generally
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   230
tests are predetermined as said above, if not the software design in
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   231
itself is flawed. The predetermined tests are stored along with the
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   232
test code in some persistent format like in a database, a text file, a
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   233
file of specific format like XML or in some other way. Let us continue
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   234
with our example of GCD function. We will keep all our test cases in a
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   235
text file, which is indeed persistent. Let us specify the format of
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   236
the test data in our file as follows.
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   237
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   238
  1. The file has multiple lines of test data.
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   239
  2. Each line in this file corresponds to a single test case.
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   240
  3. Each line consists of three comma separated coloumns:
112
0b01bb6ea6b8 Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 110
diff changeset
   241
115
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   242
     i. First two coloumns are the integers for which the GCD has to
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   243
        be computed
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   244
     ii. Third coloumn is the expected GCD to the preceding two
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   245
         numbers.
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   246
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   247
So how do we write our tests to use these test cases? Pretty simple, let
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   248
us review the machinery required first.
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   249
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   250
  1. File reading: We already have learnt this in the modules on
112
0b01bb6ea6b8 Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 110
diff changeset
   251
     Basic Python.
115
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   252
  2. Parsing the read data from the file: This just involves a using a
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   253
     **for** loop which iterates over the data line by line since we
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   254
     know that the file contains each test case as a sepate line which
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   255
     are equivalent to the file records and hence parse the data line
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   256
     by line as strings as we iterate over it and convert it to the
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   257
     required data type.
112
0b01bb6ea6b8 Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 110
diff changeset
   258
0b01bb6ea6b8 Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 110
diff changeset
   259
Since we already have all the machinery required, let us proceed writing
115
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   260
our test cases. We do not need not make any changes to the gcd
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   261
function so we will just write down the test here. Let us call our
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   262
data file gcd_testcases.dat::
112
0b01bb6ea6b8 Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 110
diff changeset
   263
115
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   264
  if __name__ == '__main__':
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   265
      for line in open('gcd_testcases.dat'):
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   266
          values = line.split(', ')
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   267
          a = int(values[0])
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   268
          b = int(values[1])
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   269
          g = int(values[2])
112
0b01bb6ea6b8 Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 110
diff changeset
   270
115
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   271
          tc = gcd(a, b)
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   272
          if tc != g:
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   273
              print "Test failed for the case a=%d and b=%d. Expected %d. Obtained %d instead." % (a, b, g, tc)
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   274
              exit(1)
112
0b01bb6ea6b8 Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 110
diff changeset
   275
115
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   276
      print "All tests passed!"
112
0b01bb6ea6b8 Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 110
diff changeset
   277
115
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   278
When we execute the gcd.py script again we will notice that all the
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   279
tests passed.
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   280
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   281
Running at the **nose**
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   282
=======================
112
0b01bb6ea6b8 Add a work-in progress section on writing realistic tests.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 110
diff changeset
   283
115
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   284
Not too far ahead we go we will start running at the nose saying of
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   285
Python developers saying that this is not sufficient to write
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   286
complicated tests in an efficient manner and writing tests for the
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   287
programs are so important that Python should provide a tool for
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   288
managing large tests. To further explain, the idea of placing the
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   289
tests with in the Python scripts and to execute them when the script
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   290
is run as a stand-alone script works well as long as we have our code
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   291
in a single Python file or as long as the tests for each script can be
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   292
run separately. But in a more realistic software development scenario,
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   293
often this is not the case. The code is spread around multiple Python
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   294
scripts, each script also called as a Python module, and also across
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   295
several Python packages.
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   296
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   297
In such a scenario what we would like to do is to create a separate
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   298
directory for holding these test. The structure of this directory is
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   299
the exact replica of the Python package hierarchy of our software to
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   300
be tested. This structure is especially useful because of the fact
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   301
that we have a one to one correspondence to our code and to its test.
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   302
Hence it is easy for us to navigate through the tests as we maintain
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   303
the existing tests and to add new tests as the code evolves. We have a
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   304
collection of tests in the specified structure. Any collection of
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   305
tests is called as the test suite for the *software package*. Hence we
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   306
shall call this directory of tests as our test suite.
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   307
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   308
Fine we have all these, but how do we make our tests aware that they
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   309
are the tests for such and such a Python module or code and when
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   310
executed must test that corresponding code? To make the lives of
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   311
Python developers and testers easy Python provides a very handy tool
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   312
called as **nose**. The name should have been pretty evident from the
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   313
heading of this section! So in the rest of this module let us discuss
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   314
how to use **nose** to write, maintain and extend our tests as the
7455326cac40 Completed the section on realistic test scenarios and introductory paragraphs on nose.
Madhusudan.C.S <madhusudancs@gmail.com>
parents: 112
diff changeset
   315
code evolves.