Skip to content

Pytest - examples

Example 1

We have a function:

def sum_args(max_value, *args):
    return 0

Let us list the test cases:

  • we pass a number in max_value and all subsequent arguments are numbers smaller than max_value, we expect the sum of all numbers
  • we pass a number in max_value and not all subsequent arguments are numbers less than max_value, we expect a sum of numbers less than or equal to max_value
  • we pass a number in max_value and not all subsequent arguments are numbers, it may happen e.g. a string, we only expect the sum of numbers smaller than max_value
  • we pass a string in max_value and all subsequent arguments are numbers, we only expect the sum of numbers less than or equal to 100 (default value)
  • we pass a string in max_value and not all subsequent arguments are numbers, we only expect the sum of numbers less than or equal to 100 (default value)

So we have 5 test cases. Let's write the tests:

def test_sum_of_elements_below_max_val():
    max_value = 10
    elements = [2, 4, 5, 3, 9, 1, 0, -2]

    expected = 22

    assert sum_args(max_value, *elements) == expected


def test_sum_of_elements_above_max_val():
    max_value = 8
    elements = [2, 4, 5, 3, 9, 1, 0, -2]

    expected = 13

    assert sum_args(max_value, *elements) == expected


def test_sum_of_elements_with_mixed_types():
    max_value = 8
    elements = [2, 4, 5, 3, 'test']

    expected = 14

    assert sum_args(max_value, *elements) == expected


def test_sum_of_elements_with_invalid_max_val():
    max_value = 'test'
    elements = [2, 4, 5, 3]

    expected = 14

    assert sum_args(max_value, *elements) == expected


def test_sum_of_elements_with_invalid_max_val_and_mixed_types():
    max_value = 'test'
    elements = [2, 4, 5, 3, 'test']

    expected = 14

    assert sum_args(max_value, *elements) == expected

Running tests:

tdd

This shows that neither passes. So we enter the first iteration - we write the code:

def sum_args(max_value, *args):
    sum_of_elements = 0
    for val in args:
        if val <= max_value:
            sum_of_elements += val

    return sum_of_elements

And the effect is better, but still not satisfactory:

tdd

We are 40% effective!

We keep improving!

We need to program a situation where there is something other than a number in argsch, let's filter it!

Let our new function look like this:

def sum_args(max_value, *args):
    sum_of_elements = 0
    for val in args:
        if isinstance(val, int) and val <= max_value:
            sum_of_elements += val

    return sum_of_elements

which gives us another test that passed:

tdd

Yay! I am happy with you :)

The next test was the default * max_value * of 100 if it was passed incorrectly. We can do it like this:

def sum_args(max_value, *args):
    sum_of_elements = 0
    max_value = 100 if not isinstance(max_value, int) else max_value
    for val in args:
        if isinstance(val, int) and val <= max_value:
            sum_of_elements += val

    return sum_of_elements

What makes us have a set of tests:

tdd

because the previous amendment corrected the missing elements.

Example 2

We assume that I have to test this function:

def capital_case(x):
    return x.capitalize()

It takes a string as an argument and changes its first letter to uppercase. If we save this function in the file * ex3.py * and create a new file named * test_ex3.py * with the contents:

from ex3 import capital_case


def test_capital_case():
    assert capital_case('Software') == 'Software'

we will pass this test.

What if we pass something other than a string in the argument?

In the previous example, we taught our function to deal with it. Here we want the function to actually throw an exception. But how to test it?

PyTest allows you to check if the code under test has raised an exception!

Before we get into that, let's see what happens when we pass an int there:

def capital_case(x):
    return x.capitalize()


capital_case(9)

the result is this:

Traceback (most recent call last):
  File "/home/mmazurek/testy2/ex3.py", line 5, in <module>
    capital_case(9)
  File "/home/mmazurek/testy2/ex3.py", line 2, in capital_case
    return x.capitalize()
AttributeError: 'int' object has no attribute 'capitalize'

As you can see, in this situation, Python throws an exception of type * AttributeError , which indicates that we are trying to use a non-existent attribute, in this case, the capitalize* function.

This is not a very good exception for the end user, so correct our function by throwing another exception:

def capital_case(x):
    if not isinstance(x, str):
        raise TypeError('Please provide a string argument')
      return x.capitalize()

To test this, we should use Pytest.rises. We can do it like this:

from ex3 import capital_case
import pytest


def test_capital_case():
    assert capital_case('Software') == 'Software'


def test_raises_exception_on_non_string_arguments():
    with pytest.raises(TypeError):
        capital_case(9)

and this will make our test pass, because the exception in such a situation is the expected value:

tdd