Unit testing is another way of thinking about testing programs. Now that your programs are divided into multiple functions, there can be testing done at a lower level than just testing the whole program.
Each function (sometimes called a unit) can be tested on its own. The header of the function should give definite ideas for tests that should be run on it. Example, if a function header says one of the parameters must be greater than zero, then testing for zero, positive and negative parameters will be useful. If a function header says that the string parameter must have all uppercase letters in it, tests could be run on the parameter to test what happens if that constraint is not followed, as well as if it is. The header is considered a "contract" between the person who wrote the unit (function) and the users of the function. The pre- conditions must be fulfilled for the user of the function to be able to rely on the behavior / return value of the function. And the post-conditions are a statement of what the function WILL do if the first part of the contract is upheld. The user has a right to depend on that statement.
In Python this is usually fairly easy to do. Once you have decided what your unit tests are going to be for a particular function, just load the program into the IDE and type the name of the function at the shell prompt with appropriate arguments. Make a note of what the return value is. Occasionally if a unit needs a library, that library will have to be imported first in the shell before the unit tests are run.
def safe_divide (n, m): # will divide n by m if m is not zero, otherwise returns None # precondition - n, m are number types (floats or ints) # postcondition - value of n/m will be returned if m is not zero, # otherwise None will be returned if m != 0: result = n / m else: result = None return result
Unit tests for this function would include
|Case Desc.||Arguments||Expected Output|
|normal, args equal||5, 5||1.0|
|normal, args not equal, numerator not multiple of denominator||7, 5||1.4|
|normal, args not equal, numerator multiple of denominator||10, 5||2.0|
|error, denominator zero||5, 0||None|
|normal, zero numerator||0, 5||0.0|
Unit testing is not complete testing of a program. The interaction between functions can also be a place for bugs to appear.