Lab 06: Testing with pytest
Objective
Time
Prerequisites
Tools
Lab Instructions
Step 1: pytest Basics & Assertions
docker run --rm zchencow/innozverse-python:latest python3 -c "
import pytest
import subprocess, sys, textwrap, tempfile, os
code = textwrap.dedent('''
# product.py + test_product.py in one block
class Product:
def __init__(self, name: str, price: float, stock: int = 0):
if not name.strip():
raise ValueError(\"name required\")
if price <= 0:
raise ValueError(f\"price must be positive, got {price}\")
if stock < 0:
raise ValueError(f\"stock cannot be negative\")
self.name = name.strip()
self.price = price
self.stock = stock
@property
def status(self): return \"active\" if self.stock > 0 else \"out_of_stock\"
def sell(self, qty: int) -> None:
if qty <= 0: raise ValueError(\"qty must be positive\")
if self.stock < qty:
raise ValueError(f\"insufficient stock: have {self.stock}, need {qty}\")
self.stock -= qty
def restock(self, qty: int) -> None:
if qty <= 0: raise ValueError(\"qty must be positive\")
self.stock += qty
# Tests
def test_create_valid_product():
p = Product(\"Surface Pro\", 864.0, 15)
assert p.name == \"Surface Pro\"
assert p.price == 864.0
assert p.stock == 15
assert p.status == \"active\"
def test_create_out_of_stock():
p = Product(\"USB-C Hub\", 29.99, 0)
assert p.status == \"out_of_stock\"
def test_name_stripped():
p = Product(\" Surface Pen \", 49.99)
assert p.name == \"Surface Pen\"
def test_invalid_name():
with pytest.raises(ValueError, match=\"name required\"):
Product(\"\", 10.0)
def test_invalid_price():
with pytest.raises(ValueError, match=\"price must be positive\"):
Product(\"Test\", -1.0)
def test_sell():
p = Product(\"Test\", 10.0, 10)
p.sell(3)
assert p.stock == 7
def test_sell_insufficient_stock():
p = Product(\"Test\", 10.0, 5)
with pytest.raises(ValueError, match=\"insufficient stock\"):
p.sell(10)
def test_restock():
p = Product(\"Test\", 10.0, 0)
p.restock(50)
assert p.stock == 50
assert p.status == \"active\"
''')
with tempfile.TemporaryDirectory() as tmp:
test_file = os.path.join(tmp, 'test_product.py')
with open(test_file, 'w') as f:
f.write(code)
result = subprocess.run(
[sys.executable, '-m', 'pytest', test_file, '-v', '--tb=short'],
capture_output=True, text=True
)
print(result.stdout[-2000:])
if result.returncode != 0:
print(result.stderr[-500:])
"Step 2: Fixtures & Parametrize
Steps 3–8: Mocking, Async Tests, Property Tests, Coverage, Test Classes, Capstone
Summary
Feature
Syntax
Use case
Further Reading
Last updated
