Chapter 1 - Pytest Fundamentals

Haiyue
6min

Chapter 1: Pytest Fundamentals

Learning Objectives
  • Understand pytest’s core concepts and advantages
  • Master pytest installation and basic usage
  • Write your first test case
  • Learn about test discovery mechanisms and naming conventions

Knowledge Points

Pytest Overview and Advantages

  • Concise syntax: Uses standard assert statements, no special assertion methods needed
  • Automatic test discovery: Automatically discovers and runs test files and test functions
  • Rich plugin ecosystem: Hundreds of plugins to extend functionality
  • Detailed failure information: Provides clear error reports and debugging information
  • Fixture support: Powerful test data and resource management mechanism
  • Parameterized testing: Easy implementation of data-driven tests

Installation and Environment Setup

# Install pytest using pip
pip install pytest

# Verify installation
pytest --version

Test Discovery Mechanism

Pytest automatically discovers tests following these naming conventions:

TypeNaming Convention
Test filestest_*.py or *_test.py
Test functionstest_*
Test classesTest*
Test methodstest_*

Basic Commands

# Run all tests
pytest

# Run specific file
pytest test_example.py

# Run specific directory
pytest tests/

# Verbose output
pytest -v

# Display local variables
pytest -l

Example Code

First Test File

# test_basic.py
def add(a, b):
    """Simple addition function"""
    return a + b

def test_add_positive_numbers():
    """Test adding positive numbers"""
    result = add(2, 3)
    assert result == 5  # Use standard assert statement

def test_add_negative_numbers():
    """Test adding negative numbers"""
    result = add(-2, -3)
    assert result == -5

def test_add_zero():
    """Test adding with zero"""
    result = add(5, 0)
    assert result == 5

Running Tests

# Run from command line
$ pytest test_basic.py -v

# Example output:
# ========================= test session starts =========================
# collected 3 items
#
# test_basic.py::test_add_positive_numbers PASSED            [ 33%]
# test_basic.py::test_add_negative_numbers PASSED            [ 66%]
# test_basic.py::test_add_zero PASSED                        [100%]
#
# ========================= 3 passed in 0.01s =========================

Using Test Classes

# test_calculator.py
class Calculator:
    """Simple calculator class"""

    def add(self, a, b):
        return a + b

    def subtract(self, a, b):
        return a - b

class TestCalculator:
    """Calculator test class"""

    def setup_method(self):
        """Execute before each test method"""
        self.calc = Calculator()

    def test_addition(self):
        """Test addition functionality"""
        assert self.calc.add(2, 3) == 5
        assert self.calc.add(-1, 1) == 0

    def test_subtraction(self):
        """Test subtraction functionality"""
        assert self.calc.subtract(5, 3) == 2
        assert self.calc.subtract(0, 5) == -5

Test Failure Example

# test_failure_example.py
def divide(a, b):
    """Division function (intentionally contains error)"""
    return a / b  # No handling for division by zero

def test_divide_success():
    """Test normal division"""
    assert divide(10, 2) == 5

def test_divide_by_zero():
    """Test division by zero (this test will fail)"""
    # Here we expect an exception, but the function crashes directly
    result = divide(10, 0)
    assert result is None  # This line will never execute

Running failed tests will provide detailed error information:

$ pytest test_failure_example.py -v

# Output includes:
# FAILURES
# test_failure_example.py::test_divide_by_zero - ZeroDivisionError: division by zero
# along with detailed call stack information

Project Structure Best Practices

project/
├── src/
│   └── calculator.py          # Source code
├── tests/
│   ├── __init__.py           # Make tests a package
│   ├── test_calculator.py    # Test file
│   └── conftest.py           # pytest configuration file
├── pytest.ini               # pytest configuration
└── requirements.txt          # Dependencies file
Tips
  • Use assert statements for assertions, pytest will automatically provide detailed failure information
  • Test function names should describe the specific scenario being tested
  • Each test should be independent, not relying on results from other tests
  • Follow the AAA pattern: Arrange, Act, Assert
Cautions
  • Ensure test files and functions follow naming conventions
  • Avoid using complex logic in tests
  • Tests should execute quickly, avoid time-consuming operations

Common Command Options

OptionFunction
-v, --verboseDisplay verbose output
-q, --quietSimplified output
-sDisplay print output
-x, --exitfirstStop at first failure
--tb=shortSimplified error traceback
--collect-onlyOnly collect tests, don’t run

With this, we’ve completed the introduction to pytest fundamentals, laying a solid foundation for further learning of advanced features.