Test Organization and Best Practices¶
Guidelines for writing maintainable and effective tests.
Mental Model
Good tests follow the AAA pattern: Arrange (set up inputs), Act (call the code), Assert (check the result). Keep each test focused on one behavior, name it after what it verifies, and organize test files to mirror your source tree. Tests that are easy to read and run are tests that actually get maintained.
Test Organization¶
Structure tests logically.
```python
Project structure:¶
project/¶
src/¶
my_module.py¶
tests/¶
test_my_module.py¶
conftest.py (shared fixtures)¶
import pytest
def function_to_test(x): return x * 2
class TestMyModule: def test_double(self): assert function_to_test(5) == 10
def test_zero(self):
assert function_to_test(0) == 0
Run: pytest tests/ -v¶
print("Tests organized by module") ```
Tests organized by module
Naming Conventions and Best Practices¶
Follow testing best practices.
```python import pytest
Good test names describe what is being tested¶
def test_add_positive_numbers(): assert 2 + 3 == 5
def test_divide_by_zero_raises_error(): with pytest.raises(ZeroDivisionError): 1 / 0
def test_string_length(): assert len("hello") == 5
Arrange-Act-Assert pattern¶
def test_user_registration(): # Arrange username = "alice" password = "secure"
# Act
registered = register_user(username, password)
# Assert
assert registered is True
def register_user(username, password): return True
print("Best practices applied") ```
Best practices applied
Exercises¶
Exercise 1.
Refactor the following test to follow the Arrange-Act-Assert pattern. The test checks that a shopping cart correctly calculates the total: items are [("apple", 1.50), ("banana", 0.75)] and the expected total is 2.25. Write both the function and the test.
Solution to Exercise 1
```python def cart_total(items): return sum(price for _, price in items)
def test_cart_total_with_multiple_items(): # Arrange items = [("apple", 1.50), ("banana", 0.75)] expected = 2.25
# Act
result = cart_total(items)
# Assert
assert result == expected
```
Exercise 2.
Write a test class TestStringUtils with three well-named test methods for a function capitalize_words(text) that capitalizes the first letter of each word. Test normal input, empty string, and already-capitalized input. Use descriptive test names.
Solution to Exercise 2
```python def capitalize_words(text): return text.title()
class TestStringUtils: def test_capitalize_words_normal_input(self): assert capitalize_words("hello world") == "Hello World"
def test_capitalize_words_empty_string(self):
assert capitalize_words("") == ""
def test_capitalize_words_already_capitalized(self):
assert capitalize_words("Hello World") == "Hello World"
```
Exercise 3.
Create a test file structure for a project with src/calculator.py and tests/test_calculator.py. Write the test file with a conftest.py that provides a calculator fixture. Include at least three tests in a TestCalculator class.
Solution to Exercise 3
```python
conftest.py¶
import pytest
class Calculator: def add(self, a, b): return a + b def subtract(self, a, b): return a - b def multiply(self, a, b): return a * b
@pytest.fixture def calculator(): return Calculator()
test_calculator.py¶
class TestCalculator: def test_add_positive_numbers(self, calculator): assert calculator.add(2, 3) == 5
def test_subtract_returns_negative(self, calculator):
assert calculator.subtract(3, 5) == -2
def test_multiply_by_zero(self, calculator):
assert calculator.multiply(5, 0) == 0
```