A Simple Example

Writing a simple unit test

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:

virtualenv venv source venv/bin/activate
virtualenv venv venv\Scripts\activate

Now we can install pytest using pip:

pip install pytest

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

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:

=================== test session starts ==================== platform win32 -- Python 3.7.7, pytest-6.0.1, py-1.9.0, pluggy-0.13.1 rootdir: M:\workspace\ba-automated-testing collected 1 item test_increase_version_number.py .[100%] ==================== 1 passed in 0.26s =====================

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:

=================== test session starts ==================== platform win32 -- Python 3.7.7, pytest-6.0.1, py-1.9.0, pluggy-0.13.1 rootdir: M:\workspace\ba-automated-testing collected 1 item test_increase_version_number.py F [100%] ========================= FAILURES ========================= ___________ test_version_1_should_increase_to_2 ____________ def test_version_1_should_increase_to_2(): version_number = 1 increased_version_number = increase_version_number(version_number) > assert increased_version_number == 3 E assert 2 == 3 test_increase_version_number.py:9: AssertionError ================= short test summary info ================== FAILED test_increase_version_number.py::test_version_1_should_increase_to_2 ==================== 1 failed in 0.18s =====================

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.

Screenshot of Pytest Integration in PyCharm

Last modified September 20, 2020