Week 14 of 16

First Tests

Write test_basics.py, run pytest, break something on purpose, and meet pytest.raises()

Day 67 60 minutes Read + Experiment

Day 67 of 80

Read First: pytest Official Docs

Before writing any code, spend 10 minutes with the official docs: pytest — Getting Started. Skim it for the structure. You don't need to absorb every detail — you'll learn by doing starting in the next section.

The Docs Are Short

The pytest "Getting Started" page is unusually well-written and brief. It shows exactly the pattern you're about to use. Pay attention to the test_sample.py example — it's the same structure you'll use all week.

Create test_basics.py

Create a new file called test_basics.py anywhere in your project. Type (don't paste) these four tests:

test_basics.py python
def test_addition():
    assert 1 + 1 == 2


def test_string_upper():
    assert "kling".upper() == "KLING"


def test_list_append():
    shots = ["wide", "close"]
    shots.append("aerial")
    assert len(shots) == 3
    assert "aerial" in shots


def test_dictionary_access():
    prompt = {"platform": "Kling", "shot": "golf swing"}
    assert prompt["platform"] == "Kling"
These tests don't import anything from the DVP project — they just test basic Python behavior. That's intentional. You're learning the pattern before applying it to real code.

Run the Tests

terminal bash
$ pytest test_basics.py -v

test_basics.py::test_addition PASSED            [ 25%]
test_basics.py::test_string_upper PASSED        [ 50%]
test_basics.py::test_list_append PASSED         [ 75%]
test_basics.py::test_dictionary_access PASSED   [100%]

=================== 4 passed in 0.02s ===================
Four green dots. Four passing tests. This is what success looks like in pytest. Notice the -v flag gives you names instead of just dots — always use it while learning.

Break It On Purpose

Edit test_addition to fail intentionally. Change the assertion so it's wrong:

test_basics.py — intentional failure python
def test_addition():
    assert 1 + 1 == 3  # wrong on purpose
Run pytest again. Read the failure output carefully — this is what you'll be reading all week when something real breaks.
terminal — failure output bash
FAILED test_basics.py::test_addition - assert 2 == 3

========================= FAILURES =========================
____________________ test_addition ____________________

    def test_addition():
>       assert 1 + 1 == 3

E       assert 2 == 3
E         +  where 2 = 1 + 1

test_basics.py:2: AssertionError
=================== 1 failed, 3 passed in 0.04s ===================
pytest shows: (1) which test failed, (2) the exact line with the arrow, (3) what value you actually got. Fix the test back to == 2 before moving on.

pytest.raises() — Testing That Errors Happen

Sometimes Raising Is the Correct Behavior

Your code should raise errors in certain situations. For example, int("not a number") should raise a ValueError. If you want to verify that your validation code raises the right error when given bad input, you need pytest.raises().

It's a context manager. If the expected exception is raised inside the with block, the test passes. If no exception is raised (or the wrong one is), the test fails.

test_basics.py — add this test python
import pytest


def test_invalid_number():
    with pytest.raises(ValueError):
        int("not a number")
This test passes when int("not a number") raises a ValueError. If you changed the argument to "42", no exception would be raised and the test would fail — because it expected an error and didn't get one.

Add two more error tests to solidify the pattern:

test_basics.py — more raises tests python
def test_key_error():
    d = {"platform": "Kling"}
    with pytest.raises(KeyError):
        _ = d["missing_key"]


def test_index_error():
    shots = ["wide", "close"]
    with pytest.raises(IndexError):
        _ = shots[99]
This pattern is what you'll use tomorrow to verify that Prompt("Pika", ...) raises InvalidPlatformError. The structure is identical — you just swap in your custom exception class.

Run the Full File

terminal bash
$ pytest test_basics.py -v

test_basics.py::test_addition PASSED             [ 14%]
test_basics.py::test_string_upper PASSED         [ 28%]
test_basics.py::test_list_append PASSED          [ 42%]
test_basics.py::test_dictionary_access PASSED    [ 57%]
test_basics.py::test_invalid_number PASSED       [ 71%]
test_basics.py::test_key_error PASSED            [ 85%]
test_basics.py::test_index_error PASSED          [100%]

=================== 7 passed in 0.03s ===================
Seven green. The raises tests pass because each exception was correctly raised inside the with pytest.raises() block. This is the foundation you'll build on tomorrow.

Experiment: Write Your Own Tests

Your Turn

Before tomorrow, write at least 3 more tests of your own. Pick any Python behavior you've used in this course — string formatting, list operations, dictionary lookups, file paths, whatever. The goal is to make the test_ naming and assert pattern feel automatic.

Some ideas to try:

End of Day Checklist

Tomorrow

Day 68 is where it gets real. You'll create a tests/ folder inside the DVP Prompt Vault project and write comprehensive tests for the Prompt and PromptLibrary classes — including the tmp_path fixture for safe file operations.