What is Pytest?

Pytest is an open source python testing framework that allows for super easy standing up of a test framework, collection of tests, and general python goodness. This tutorial shows the basics of how a basic pytest project works and how a simple setup works. Throughout this, I'm using Python 3.7.3, Pytest 5.0.1, and bash on Ubuntu 19.10. The pytest syntax and knowledge should still be applicable to non *nix systems.

Installation

Pytest is available through pip. Assuming Python and pip are installed run: pip install pytest

Create the Project Directory

Create a new folder called pytest-learning and create the file my_first_test.py within it. I placed it in my home, but they could be anywhere. By default, these commands will place the files in your current working directory.

mkdir pytest-learning touch pytest-learning/my_first_test.py

This file will contain our first pytests.

A Basic Pytest and Pytest Report

Add the following lines to my_first_test.py

def test_my_first_ever():
    '''
    This test simply passes through!
    By default pytest assumes a test that returns is a test that passes
    '''
    pass

Let's run this test, then talk through it. Navigate inside pytest-learning (cd pytest-learning) and run pytest. You should see an output like:

image.png

Pytest right out of the box creates a neat looking test report. It shows the start of the pytest session, platform + version information, and the name of the test file ran. The "." is pytest's shorthand way of showing that the test has passed. There will be a "." for every test ran. Since there's only one test in my_first_test.py, we only see one dot. Finally, it ends with how long the session took and how many tests passed.

As mentioned in the doc string, pytest by default will pass any test that doesn't check anything. Typically you'd want to write a test to check a condition which is where the assert statement comes in.

The Assert Statement

Assert statements are ubiquitous throughout most programming languages. They're often used as a way for developers to check at runtime that their code is working properly. Within a pytest, assert is used to create pass/fail conditions. When the statement after assert evaluates to true, the test continues until either the test is done or another assert fails. When the statement after assert evaluates to false, the test fails and pytest moves on to the next test in the sequence. It does not run the rest of the lines in the test by default. Let's look at some examples to illustrate this. These functions are all in my_first_test.py

def test_evaluate_true():
    '''
    This test passes with an assert. 1 + 1 == 2 evaluates to True
    so this test will pass.
    '''
    assert 1 + 1 == 2

def test_evaluate_false():
    '''
    This test fails at the second assert statement. Notice how
    it fails the entire test despite the other two assert statements
    evaluating to True.
    '''
    assert 2 + 2 == 4
    assert 1 + 1 == 3
    assert True

Let's run pytest in the pytest-learning folder and look at the result.

image.png

Notice how there are two "." and an F! The two "." represent "test_my_first_ever" and "test_evaluate_true" while the F represents "test_evaluate_false". Pytest makes it clear which exact test is failing and at the exact assert statement. The line labeled ">" is the assert statement that failed. This is labeled failure rather than error on purpose. In a general pytest configuration, failure means an assert within a test case evaluated to false. An error means the python file failed to execute properly. As shown in the this image, test_evaluate_false failed an assert statement, so all of the code preceding that ran (but not neccessarily correctly!).

If we fix the second assert in test_evaluate_false (i.e. assert 1 + 1 == 3) we can get a nice three tests that pass.

image.png

Quick Note on Naming

Pytest is very particular about the names it uses. By default it will only use functions that begin with test_ as "pytests" and will only look in files that being with test_ or end with _test.py See more about that here.

Stay tuned for part 2 where we'll take a look at fixtures, command line options and conftest.py! If you have any comment shoot me a message on github!