0
0
PyTesttesting~15 mins

Test classes in PyTest - Deep Dive

Choose your learning style9 modes available
Overview - Test classes
What is it?
Test classes in pytest are a way to group related test functions inside a class. They help organize tests logically without needing to inherit from any special base class. Each method inside the class that starts with 'test_' is treated as an individual test by pytest.
Why it matters
Without test classes, tests can become scattered and hard to manage as projects grow. Grouping tests in classes improves readability and maintainability. It also allows sharing setup code easily between tests, reducing duplication and errors. Without this, testing large projects would be chaotic and error-prone.
Where it fits
Before learning test classes, you should understand basic pytest test functions and how pytest discovers tests. After mastering test classes, you can learn about fixtures, parameterized tests, and test inheritance to write more powerful and reusable tests.
Mental Model
Core Idea
Test classes are containers that group related test functions and share setup code to keep tests organized and efficient.
Think of it like...
Test classes are like folders in a filing cabinet where you keep related documents together so you can find and manage them easily.
┌─────────────────────┐
│     Test Class      │
│ ┌───────────────┐   │
│ │ setup_method  │   │
│ │ test_method_1 │   │
│ │ test_method_2 │   │
│ └───────────────┘   │
└─────────────────────┘
Build-Up - 7 Steps
1
FoundationBasic pytest test functions
🤔
Concept: Understand how pytest discovers and runs simple test functions.
In pytest, any function starting with 'test_' is a test. For example: def test_addition(): assert 1 + 1 == 2 Running pytest will find and run this test automatically.
Result
pytest runs the test and reports pass if the assertion is true.
Knowing how pytest finds tests is essential before grouping them into classes.
2
FoundationCreating a simple test class
🤔
Concept: Learn how to define a test class and add test methods inside it.
A test class is a normal Python class whose name starts with 'Test'. Inside, methods starting with 'test_' are tests: class TestMath: def test_add(self): assert 1 + 1 == 2 def test_subtract(self): assert 2 - 1 == 1 pytest will run both methods as separate tests.
Result
pytest runs both test methods and reports their results separately.
Grouping tests in classes helps organize related tests together logically.
3
IntermediateUsing setup and teardown methods
🤔Before reading on: do you think setup_method runs once per class or once per test method? Commit to your answer.
Concept: Learn how to run code before and after each test method in a class using setup_method and teardown_method.
Inside a test class, define setup_method(self, method) to run before each test method, and teardown_method(self, method) to run after: class TestExample: def setup_method(self, method): self.value = 10 def teardown_method(self, method): del self.value def test_value(self): assert self.value == 10 This runs setup before each test, ensuring fresh state.
Result
Each test method runs with setup_method called before and teardown_method after, isolating tests.
Understanding per-test setup prevents tests from affecting each other and causing flaky failures.
4
IntermediateSharing state with class variables
🤔Before reading on: do you think class variables are shared across all test methods or unique per method? Commit to your answer.
Concept: Learn how class variables can hold shared state for all test methods in a class.
You can define variables at the class level to share data: class TestCounter: count = 0 def test_increment(self): TestCounter.count += 1 assert TestCounter.count == 1 def test_increment_again(self): TestCounter.count += 1 assert TestCounter.count == 2 Class variables persist across test methods, unlike instance variables.
Result
Test methods see the updated class variable value, showing shared state.
Knowing shared state behavior helps avoid unintended test dependencies and flaky tests.
5
IntermediateCombining fixtures with test classes
🤔Before reading on: do you think fixtures can be used inside test classes as easily as with functions? Commit to your answer.
Concept: Learn how pytest fixtures can be used with test classes to provide setup data or resources.
Fixtures can be passed as method arguments inside test classes: import pytest @pytest.fixture def sample_data(): return [1, 2, 3] class TestData: def test_sum(self, sample_data): assert sum(sample_data) == 6 pytest injects the fixture automatically.
Result
Test method receives fixture data and runs assertion successfully.
Using fixtures with classes combines organization with reusable setup, improving test design.
6
AdvancedAvoiding pitfalls with test class naming
🤔Before reading on: do you think pytest runs tests in classes named 'Tests' or only 'Test'? Commit to your answer.
Concept: Understand pytest's test discovery rules for classes and how naming affects which tests run.
pytest only collects classes whose names start with 'Test' and do not have an __init__ method. For example: class Tests: def test_fail(self): assert False This class is ignored by pytest. Rename to 'Test' to run tests. Also, classes with __init__ are ignored because pytest expects no-argument constructors.
Result
Tests in incorrectly named classes are skipped silently, causing missing test coverage.
Knowing discovery rules prevents silent test omissions and ensures all tests run.
7
ExpertUsing inheritance in test classes
🤔Before reading on: do you think test methods in a base class run automatically when inherited? Commit to your answer.
Concept: Learn how test classes can inherit from base classes to reuse test methods and setup code.
You can define a base test class with common tests or setup: class BaseTest: def test_common(self): assert True class TestFeature(BaseTest): def test_specific(self): assert True pytest runs both test_common and test_specific from TestFeature. Be careful: base classes without 'Test' prefix are not collected directly.
Result
Inherited test methods run as part of child test classes, enabling code reuse.
Understanding inheritance in tests allows building modular, DRY test suites but requires careful naming to avoid missing tests.
Under the Hood
pytest discovers tests by scanning files and looking for functions or methods starting with 'test'. For classes, it only collects those named starting with 'Test' and without __init__. Each test method is called separately, creating a fresh instance of the test class for isolation. Setup and teardown methods are called around each test method. Fixtures are injected by pytest using function argument names and dependency injection.
Why designed this way?
pytest was designed for simplicity and flexibility. Using naming conventions instead of inheritance lowers barriers for beginners. Creating a new instance per test method ensures isolation and prevents shared state bugs. Fixtures provide a powerful, reusable setup mechanism that integrates smoothly with test classes. This design balances ease of use with advanced features.
Test Discovery Flow:

[Source Files]
     │
     ▼
[Find classes named 'Test*']
     │
     ▼
[Find methods named 'test_*']
     │
     ▼
[For each test method]
     │
     ├─> Create new instance of test class
     ├─> Call setup_method (if exists)
     ├─> Inject fixtures as arguments
     ├─> Run test method
     ├─> Call teardown_method (if exists)
     └─> Report result
Myth Busters - 4 Common Misconceptions
Quick: Does pytest run tests in any class named 'Tests'? Commit to yes or no.
Common Belief:pytest runs tests in any class whose name contains 'Test', like 'Tests' or 'MyTestSuite'.
Tap to reveal reality
Reality:pytest only collects classes whose names start exactly with 'Test'. Classes named 'Tests' or 'MyTestSuite' are ignored.
Why it matters:Misnaming test classes causes tests to be silently skipped, leading to false confidence and missing test coverage.
Quick: Do setup_method and teardown_method run once per class or once per test method? Commit to your answer.
Common Belief:setup_method and teardown_method run once before and after all tests in the class.
Tap to reveal reality
Reality:They run before and after each individual test method, not once per class.
Why it matters:Misunderstanding this can cause tests to share state unexpectedly, leading to flaky or incorrect test results.
Quick: Are class variables reset between test methods? Commit to yes or no.
Common Belief:Class variables are reset for each test method, so tests are isolated by default.
Tap to reveal reality
Reality:Class variables persist across test methods because pytest creates a new instance but the class object is shared.
Why it matters:Shared class variables can cause tests to interfere with each other, causing unpredictable failures.
Quick: Does pytest run test methods defined in base classes automatically when inherited? Commit to yes or no.
Common Belief:pytest only runs test methods defined in the actual test class, not inherited ones.
Tap to reveal reality
Reality:pytest runs test methods inherited from base classes as long as the child class is collected.
Why it matters:Knowing this allows reuse of test code via inheritance but requires careful class naming to ensure base classes are not collected directly.
Expert Zone
1
pytest creates a new instance of the test class for each test method, so instance variables do not persist between tests, but class variables do.
2
Fixtures can be used as class-level setup by combining them with autouse=True or by using class-scoped fixtures, enabling efficient resource management.
3
Using __init__ in test classes disables pytest's test collection for that class because pytest expects no-argument constructors.
When NOT to use
Avoid test classes when tests do not share setup or logical grouping; simple test functions with fixtures are clearer. For complex setup, prefer fixtures over setup_method for better reuse and flexibility.
Production Patterns
In large projects, test classes group tests by feature or module. Common patterns include using base test classes for shared tests, combining fixtures for setup, and careful naming to control test discovery. Setup and teardown methods are often replaced by fixtures for better modularity.
Connections
Fixtures
builds-on
Understanding test classes helps use fixtures effectively to share setup and teardown logic across grouped tests.
Object-Oriented Programming
same pattern
Test classes use OOP concepts like classes, methods, and inheritance to organize and reuse test code, showing how programming principles apply in testing.
Project Management
opposite
Just as test classes organize code logically, project management organizes tasks and teams; both improve clarity and efficiency by grouping related items.
Common Pitfalls
#1Tests in classes named incorrectly are not run.
Wrong approach:class Tests: def test_fail(self): assert False
Correct approach:class TestSuite: def test_fail(self): assert False
Root cause:pytest only collects classes starting with 'Test', so 'Tests' is ignored.
#2Using __init__ in test classes breaks test discovery.
Wrong approach:class TestExample: def __init__(self): self.value = 1 def test_value(self): assert self.value == 1
Correct approach:class TestExample: def setup_method(self, method): self.value = 1 def test_value(self): assert self.value == 1
Root cause:pytest expects no-argument constructors; __init__ disables test collection.
#3Sharing state via class variables causes test interference.
Wrong approach:class TestCounter: count = 0 def test_one(self): TestCounter.count += 1 assert TestCounter.count == 1 def test_two(self): TestCounter.count += 1 assert TestCounter.count == 1 # Fails
Correct approach:class TestCounter: def setup_method(self, method): self.count = 0 def test_one(self): self.count += 1 assert self.count == 1 def test_two(self): self.count += 1 assert self.count == 1
Root cause:Class variables persist across tests; instance variables reset per test.
Key Takeaways
pytest test classes group related test methods to organize and manage tests better.
pytest discovers test classes by name starting with 'Test' and ignores classes with __init__ methods.
setup_method and teardown_method run before and after each test method, ensuring test isolation.
Class variables are shared across test methods, while instance variables are reset per test.
Combining fixtures with test classes enables powerful, reusable setup and teardown logic.