A Simple Example
Let’s start by writing a test for a simple function that increases a version number.
The function looks like this and is placed in a file named increase_version_number.py
:
def increase_version_number(version_number):
# type: (int) -> int
return version_number + 1
A Test Framework
Before we can start writing a test, we need something that helps us execute our tests.
A test, in general, can be straightforward.
We need to verify the result of a function.
In the case of the increase_version_number
function, we need to call the function and check if the result is correct.
But that’s very tedious if we end up having multiple tests and want a report about which tests failed and which didn’t.
Luckily, we don’t have to implement something like that on our own. A test framework can do the job for us. The test framework will take care of finding all tests in the source files, execute them, gather the result, and generate a report for us. Our test framework of choice will be pytest, which is very popular in the Python ecosystem. An alternative to pytest would be the unittest unit testing framework, which already ships with Python. But pytest tends to be more pythonic and easy to use, so we will go with pytest.
Setting up pytest
Pytest can be easily installed with the Python package installer pip. It’s recommended to install it inside a virtual environment. Open a terminal to create a new virtual environment and activate it:
Now we can install pytest using pip:
We are ready to write our first test function.
Our first test
Create a file named test_increase_version_number.py
and place the test function inside.
The test function looks like this:
from increase_version_number import increase_version_number
def test_version_1_should_increase_to_2():
version_number = 1
increased_version_number = increase_version_number(version_number)
assert increased_version_number == 2
The naming is important. Module and function names need to start with test_
.
Otherwise, pytest does not find them.
Let’s analyze what happens in the test function.
It consists of two steps.
In the first step, increase_version_number
is called with a version number, and the result is stored.
It’s called the act step.
In the second step, the stored result is verified.
An assertion does this.
An assertion verifies a boolean expression.
If the expression is not true, the test will fail.
In this case, the increased version number is expected to be the version number increased by one.
That’s called the assert step.
Usually, there is also an arrange step. In the arrange step, preparations are done that are required to call the test function. In this simple example, this is not necessary.
Invoking the test and see results
To execute the tests, we simply invoke pytest from the terminal:
Pytest gathers all modules starting with test_
and executes all functions starting with test_
inside.
After executing all test functions, a report is printed to the console:
In our case all tests passed.
To see what happens when a test fails, simply change one line in the test function:
from increase_version_number import increase_version_number
def test_version_1_should_increase_to_2():
version_number = 1
increased_version_number = increase_version_number(version_number)
assert increased_version_number == 3
Pytest will show us the error:
IDE Integrations
IDEs offer functionality to run tests by pressing one button. This is more convinient than executing tests from a terminal. PyCharm for example offers a way to run individual test functions by clicking the run icon next to a test function.
To use the pytest integration inside PyCharm, open Settings/Preferences | Tools | Python Integrated Tools and choose pytest as your default test runner. Once pytest is activated, you can can execute tests from PyCharm in a convinient way. For more details of the pytest integration in PyCharm, see the PyCharm documentation.