Pytest
Pytest is the standard testing framework for modern Python. Master professional testing strategies used by real engineering teams.
Learn Python, JavaScript, Java and more with free interactive lessons, real projects and AI-powered help. Beginner-friendly.
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.
This lesson takes you from basic testing → professional test suite architecture.
🔥 1. Why pytest?
🧪 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:
🔁 5. Setup & Teardown with yield
🧪 6. Parametrised Tests
Instead of writing multiple duplicate tests, use parametrisation:
🧪 7. Basic Mocking
🔧 Factory Fixtures
🧠 Combining Fixtures + Parametrisation
🔐 Monkeypatching
🛰 Mocking External APIs
🧪 Spy Objects
🧪 Test Suite Structure
🧱 Integration Testing
🧱 Mocking Time and Randomness
🎓 Summary
You've learned professional pytest strategies:
📋 Quick Reference — pytest
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.