Subsection 6.3.1 Introduction
A
test case expresses requirements for a program, in a way that can be checked automatically. Specifically, a test asserts something about the state of the program at a particular point in its execution. A
unit test is an automatic procedure used to validate that individual units of code are working properly. A function is one form of a unit. A collection of these unit tests is called a
test suite.
We have previously suggested that it’s a good idea to first write down comments about what your code is supposed to do, before actually writing the code. It is an even better idea to write down some test cases before writing a program.
There are several reasons why it’s a good habit to write test cases.
Before we write code, we have in mind what it should do, but those thoughts may be a little vague. Writing down test cases forces us to be more concrete about what should happen.
As we write the code, the test cases can provide automated feedback. You’ve actually been the beneficiary of such automated feedback via test cases throughout this book in some of the activecode windows and almost all of the exercises. We wrote the code for those test cases but kept it hidden, so as not to confuse you and also to avoid giving away the answers. You can get some of the same benefit from writing your own test cases.
In larger software projects, the set of test cases can be run every time a change is made to the code base. Unit tests check that small bits of code are correctly implemented.
One way to implement unit tests in Python is with
assert
.
Following the word assert there will be a python expression.
If that expression evaluates to the Boolean False
, then the interpreter will raise a runtime error.
If the expression evaluates to True
, then nothing happens and the execution goes on to the next line of code.
Take a look at the way assert is used in the following code.
In the code above, we explicitly state some natural assumptions about how truncated division might work in python. It turns out that the second asumption is wrong:
9.0//5
produces
2.0
, a floating point value!
The python interpreter does not enforce restrictions about the data types of objects that can be bound to particular variables; however, type checking could alert us that something has gone wrong in our program execution. If we are assuming at that
x
is a list, but it’s actually an integer, then at some point later in the program execution, there will probably be an error. We can add
assert
statements that will cause an error to be flagged sooner rather than later, which might make it a lot easier to debug.
Checkpoint 6.3.1.
When
assert x==y
is executed and x and y have the same values, what will happen?
A runtime error will occur
The expression ``x==y`` evaluates to ``True``
A message is printed out saying that the test failed.
The expression ``x==y`` evaluates to ``True``
x will get the value that y currently has
``x==y`` is a Boolean expression, not an assignment statement
Nothing will happen
The expression ``x==y`` evaluates to ``True``
A message is printed out saying that the test passed.
When an assertion test passes, no message is printed.
Subsection 6.3.2 assert
with for
loops
Why would you ever want to write a line of code that can never compute anything useful for you, but sometimes causes a runtime error? For all the reasons we described above about the value of automated tests. You want a test that will alert that you that some condition you assumed was true is not in fact true. It’s much better to be alerted to that fact right away than to have some unexpected result much later in your program execution, which you will have trouble tracing to the place where you had an error in your code.
Why doesn’t
assert
print out something saying that the test passed? The reason is that you don’t want to clutter up your output window with the results of automated tests that pass. You just want to know when one of your tests fails. In larger projects, other testing harnesses are used instead of
assert
, such as the python
unittest
module. Those provide some output summarizing tests that have passed as well as those that failed. In this textbook, we will just use simple
assert
statements for automated tests.
In the code below,
lst
is bound to a list object. In python, not all the elements of a list have to be of the same type. We can check that they all have the same type and get an error if they are not. Notice that with
lst2
, one of the assertions fails.