Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Testing with pytest

Tip

For this chapter, you will only be creating and testing locally. The GitHub Classroom is already setup with tests to grade your solutions.

Install pytest locally

On your machine (using the same Python you use for the assignment—see the virtual environments chapter at the end of the book if you use a venv):

pip install pytest

Then run from your project root (where your code and the autograder’s layout expect to run):

pytest

A function you can test

Prefer testing functions that return values as they are often easier to assert:

# greeting.py
# a function that accepts a str typed argument and returns a str typed value
def greeting(name: str) -> str:
    return f"Hello, {name}!"
# tests/test_greeting.py  (LOCAL ONLY — see warning below)
from greeting import greeting

def test_greeting():
    assert greeting("World") == "Hello, World!"

Run: pytest test_greeting.py -v

Example test output

pytest -v 
===================================================================================== test session starts =====================================================================================
platform darwin -- Python 3.14.3, pytest-9.0.2, pluggy-1.6.0 -- /Users/user/.local/pipx/venvs/pytest/bin/python
cachedir: .pytest_cache
rootdir: /Users/user/Documents/Student-Views/pygames
collected 1 item                                                                                                                                                                              

test_greeting.py::test_greeting_name PASSED                                                                                                                                             [100%]

====================================================================================== 1 passed in 0.00s ======================================================================================

Tip

pytest will automatically find your files that have the “test” prefix or suffix and use it. The -v is nice to see more details about the test.

Testing output

Using capsys

To check print("Hello, World!"), capture stdout with pytest’s capsys fixture:

# hello.py
def say_hello() -> None:
    print("Hello, World!")
# tests/test_hello.py  (LOCAL ONLY)
from hello import say_hello

def test_say_hello_prints(capsys):
    say_hello()
    captured = capsys.readouterr()
    assert captured.out.strip() == "Hello, World!"

captured.out is everything printed to standard output during the test.

Parametrize (optional)

Run one test logic with many inputs:

import pytest

@pytest.mark.parametrize("n,expected", [(1, 1), (2, 4), (3, 9)])
def test_square(n, expected):
    assert n * n == expected

That setup is useful when some code under test should map each input to a known result—here, squaring integers. A tiny module might define:

# math_utils.py
def square(n: int) -> int:
    return n * n

The same parametrized table then targets that function: use assert square(n) == expected in the test body instead of inlining n * n, so the examples exercise your implementation, not only the math in the test.

Final Example

Here is one final example complete with test output. For this one, the main program is quite simple, just like what you have seen already.

def main() -> None:
    # intentionally missing the comma "," after Hello
    print("Hello World!")    

if __name__ == "__main__":
    main()

When you run it, you should hope to see this:

➜  hello git:(main) ✗ python3 hello.py 
Hello World!

To test, you could make this:

# tests/test_hello.py

import pytest
import hello  # ← imports the hello.py module


def test_main_prints_hello_world(capsys):
    """Check that main() prints exactly 'Hello, World!'"""
    
    # Run the student's main function
    hello.main()
    
    # Capture everything that was printed
    captured = capsys.readouterr()
    
    # Clean up the output (remove extra spaces/newlines)
    output = captured.out.strip()
    expected = "Hello, World!"
    
    # Use pytest.fail() instead of assert → no ugly diff at the bottom!
    if output != expected:
        pytest.fail(f"Expected exactly this: {expected} But your main() printed: \
{output}")

The output of this failed program looks like this:

➜  hello git:(main) ✗ pytest              
================================================================================= test session starts =================================================================================
platform darwin -- Python 3.14.3, pytest-9.0.2, pluggy-1.6.0
rootdir: /Users/user/Documents/IntroToPythonTemplate/IntroToPythonTemplate/hello
collected 1 item                                                                                                                                                                      

test_hello.py F                                                                                                                                                                 [100%]

====================================================================================== FAILURES =======================================================================================
____________________________________________________________________________ test_main_prints_hello_world _____________________________________________________________________________

capsys = <_pytest.capture.CaptureFixture object at 0x10be817f0>

    def test_main_prints_hello_world(capsys):
        """Check that main() prints exactly 'Hello, World!'"""
    
        # Run the student's main function
        hello.main()
    
        # Capture everything that was printed
        captured = capsys.readouterr()
    
        # Clean up the output (remove extra spaces/newlines)
        output = captured.out.strip()
        expected = "Hello, World!"
    
        # Use pytest.fail() instead of assert → no ugly diff at the bottom!
        if output != expected:
>           pytest.fail(f"Expected exactly this: {expected} But your main() printed: \
    {output}")
E           Failed: Expected exactly this: Hello, World! But your main() printed: Hello World!

test_hello.py:20: Failed
=============================================================================== short test summary info ===============================================================================
FAILED test_hello.py::test_main_prints_hello_world - Failed: Expected exactly this: Hello, World! But your main() printed: Hello World!
================================================================================== 1 failed in 0.05s ==================================================================================

Your Turn

Note

Reminder, because there is no assigment for this chapter, there is no classroom repo to push your code.

Recreate what was shown above under A function you can test but modify it a bit. Instead of the greeting function accepting a str parameter, have it accept an int parameter for a zip code. Optionally, this is a great spot to practice parameter testing.

The return statement can still be a formatted string. For example, return f"Zip code {zipcode}".