Unit testing
You are getting the first edition of all these pages. Please let me know if you find an error!
Assertions are the basis of modern automated testing. Developers write test code in source files that are separate from the main program code. We have our program code in sample.py
and the test code will be in test_sample.py
. This is a common naming convention.
In practice, the test code will be kept in a separate directory from the program code.
Testing sample.py
Now, let’s use our assert
to test the correctness of the functions in sample.py
.
- Comment out all the code in
test_sample.py
- Add the line
import sample
. In Python, this makes the content ofsample.py
accessible to code intest_sample.py
.1 - Now let’s convert those
print(...)
statements fromsample.py
intoassert
statements intest_sample.py
.test_sample.py
should now have the following:test_sample.py
import sample # We import the filename without the .py assert sample.palindrome_check("kayak") # the function should return True, giving "assert True" assert sample.palindrome_check("Kayak") assert sample.palindrome_check("moose") is False # the function should return False, giving "assert False is False", which is True assert sample.is_prime(1) is False assert sample.is_prime(2) assert sample.is_prime(8) is False assert sample.reverse_string("press") == "sserp" # checking result for equality with expected assert sample.reverse_string("alice") == "ecila" assert sample.reverse_string("") == "" print("All assertions passed!")
Point 1: We access the functions in sample.py
by calling, e.g., sample.palindrome_check(...)
. The prefix sample.X
tells Python “go into the sample
module and call the function named X.” We would get an error if we called only sample.palindrome(...)
because Python would be looking in the current running file, which has no such function defined in it.
Point 2: In Python, you should check if a value is True
or False
using is
. The is
operator returns a boolean. You could also type x == True
or x == False
. Either form will work, but is
is preferred2.
Point 3: Remember that palindrome_check()
and is_prime()
return True/False themselves. We are simply verifying that they are returning the correct value. reserve_string()
returns a string value, so we need to compare using ==
to an expected value.
Point 4: The program will crash with an AssertionError
if any of the assert
statements are False
. Mess up one of the assertions to verify this.
Exercise
- Go to
sample.py
and define a function namedpower()
that takes two parameters,x
andy
, and returns the computed result ofxʸ
. - Add
assert
statements totest_sample.py
to verify your function behaves correctly.
Unit tests
The file test_sample.py
is what software engineers call an automated unit test. Unit tests test individual an individual classes or source files3. Unit tests are usually written by the same developer who wrote the program code.
Our automated unit test now calls functions and use assert
statements to verify that they are returning the expected results. If an assertion fails, the test fails.
What does it mean if a test fails? One of two things:
- Either there is something wrong in the program code. Maybe there is a logic error.
- The test code itself has a mistake in its logic.
Regardless, if a test fails, you need to figure out why. A good unit test will systematically exercise all the logic of the function or module under test. This can help uncover flaws in the program code. We will discuss strategies to do this in subsequent lessons.
We also need a way to run the test code and accumulate the results in a useful way. We will do this in the next lab.
Knowledge check
- Question: Suppose you wanted to test a function named
get_patient_priority(str)
inhospital.py
. What would you have to do to call the function from your test code? - Question: The right hand side of an
assert
statement can be any expression (simple or complex) as long as it evaluates to _____ or _____. - Question: Who writes unit tests?
- Question: The name for a test that tests an individual module is a ______ test.
- Question: Why do you think we write separate
assert
statements for each function input, rather than oneassert
statement that calls the function multiple times with different inputs? That is, why not doassert sample.reverse_string("alice") == "ecila" and sample.reverse_string("") == ""
?
In Python parlance, a single file is called a module. You can create complicated modules that are collections of multiple source files. This is how many popular Python libraries like
random
work, as do third party libraries likepytorch
andkeras
used for machine learning. It is a way to bundle functions and classes for convenient use in source code. ↩︎If you are dying to know the difference between
x is False
andx == False
, it’s because many other values are equivalent to True and False when using==
. Empty values, such as0
or[]
are== False
(try it). But onlyFalse is False
. Similarly, onlyTrue is True
, but1 == True
. ↩︎The unit is usually a single class. However, in our case, there is no class, but a collection of functions in a file. Some people treat a file as a unit. But a file can have multiple classes in it. The definition of a unit is a bit fuzzy, but usually refers to either a class or a single file. ↩︎