Pytest

Pytest is the standard testing framework for modern Python. Master professional testing strategies used by real engineering teams.

Part of the free Python course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

What You'll Master

This lesson takes you from basic testing → professional test suite architecture.

Part 1: Core pytest — Fixtures, Parametrisation & Basic Mocking

🔥 1. Why pytest?

Feature

pytest

unittest

Assertion syntax

assert x == y

self.assertEqual(x, y)

Boilerplate

None — just functions

Classes required

Fixtures

Powerful, injectable

setUp/tearDown only

Parametrisation

Built-in decorator

Manual loops

Plugin ecosystem

Huge (1000+ plugins)

Limited

🧪 2. Basic Test Structure

⚙️ 3. What Is a Fixture?

A fixture is reusable setup logic that you can "inject" into tests via function arguments.

🧱 4. Fixture Scopes

By default, fixtures are function-scoped. You can control lifespan with scope:

Scope

Runs

Use Case

function

Once per test

Safest, most isolated (default)

class

Once per class

Related tests share instance

module

Once per file

Expensive setup (DB connections)

session

Once per test run

Global resources (app config)

🔁 5. Setup & Teardown with yield

🧪 6. Parametrised Tests

Instead of writing multiple duplicate tests, use parametrisation:

🧪 7. Basic Mocking

Part 2: Advanced Fixtures & Mocking

🔧 Factory Fixtures

🧠 Combining Fixtures + Parametrisation

🔐 Monkeypatching

🛰 Mocking External APIs

🧪 Spy Objects

Part 3: Professional Test Suite Architecture

🧪 Test Suite Structure

🧱 Integration Testing

🧱 Mocking Time and Randomness

🎓 Summary

You've learned professional pytest strategies:

📋 Quick Reference — pytest

Syntax

What it does

def test_fn():

Define a test (must start with test_)

@pytest.fixture

Reusable setup/teardown function

@pytest.mark.parametrize

Run test with multiple inputs

pytest.raises(ValueError)

Assert an exception is raised

mocker.patch('module.fn')

Mock a function with pytest-mock

You can now write fixtures, parametrised tests, and mocks — the full professional pytest toolkit used at tech companies worldwide.

Up next: CLI Tools — build polished command-line applications with argparse and Typer.

Practice quiz

How do pytest tests check conditions?

  • self.assertEqual(x, y)
  • A plain assert statement, e.g. assert add(2, 3) == 5
  • expect(x).toBe(y)
  • check(x == y)

Answer: A plain assert statement, e.g. assert add(2, 3) == 5. pytest uses Python's built-in assert — no special methods or boilerplate classes required.

By naming convention, pytest discovers test functions that...

  • start with test_
  • end with _test
  • are inside a Test class only
  • have a @test decorator

Answer: start with test_. Files are test_*.py and functions start with test_ — that's how pytest finds them.

What is a pytest fixture?

  • A failed test
  • Reusable setup logic injected into tests via function arguments
  • A mocking library
  • A configuration file

Answer: Reusable setup logic injected into tests via function arguments. Fixtures provide reusable setup/teardown that tests receive as arguments.

What is the DEFAULT fixture scope?

  • session
  • module
  • class
  • function

Answer: function. Fixtures are function-scoped by default — fresh for each test, the safest and most isolated option.

Which scope runs a fixture only ONCE per entire test run?

  • function
  • class
  • module
  • session

Answer: session. session scope creates one instance for the whole run — ideal for global resources like app config.

In a fixture, what does the code AFTER a yield statement do?

  • Provides the value to the test
  • Runs as teardown after the test finishes
  • Skips the test
  • Nothing

Answer: Runs as teardown after the test finishes. yield returns the value; the lines after yield run as teardown once the test completes.

Why use @pytest.mark.parametrize?

  • To mock external systems
  • To run one test function with many input/output cases
  • To set fixture scope
  • To skip slow tests

Answer: To run one test function with many input/output cases. Parametrisation runs the same test across multiple inputs instead of duplicating test functions.

After fake_api.get.return_value = {'name': 'Boopie'}, what does fetch_user(fake_api) return for result['name']?

  • None
  • Boopie
  • An error
  • 'name'

Answer: Boopie. A Mock's return_value is what the call yields, so api.get('/user') returns that dict.

What does fake_api.get.assert_called_once_with('/user') verify?

  • That get returned '/user'
  • That get was called exactly once with that argument
  • That get raised an exception
  • That get is a real API

Answer: That get was called exactly once with that argument. It asserts the mock was called exactly one time with the given argument — a key way to verify behavior.

Which pytest construct asserts that a block raises a specific exception?

  • pytest.raises(ValueError)
  • pytest.expect(ValueError)
  • assert ValueError
  • pytest.catch(ValueError)

Answer: pytest.raises(ValueError). with pytest.raises(ValueError): ... passes only if that exception is raised inside the block.

Continue this course