0
0
PyTesttesting~15 mins

Test functions in PyTest - Deep Dive

Choose your learning style9 modes available
Overview - Test functions
What is it?
Test functions are small pieces of code that check if parts of your program work correctly. In pytest, these functions start with 'test_' and use simple assertions to compare expected and actual results. They help find mistakes early by running automatically. Anyone can write them without special setup.
Why it matters
Without test functions, bugs can hide unnoticed and cause bigger problems later. They save time and effort by catching errors early, making software more reliable and easier to fix. Imagine building a house without checking if each part is solid; test functions are like inspecting each brick before moving on.
Where it fits
Before learning test functions, you should know basic Python programming and how to write simple functions. After mastering test functions, you can learn about test fixtures, parameterized tests, and test organization for bigger projects.
Mental Model
Core Idea
A test function is a small, automatic check that confirms a specific part of your code behaves as expected.
Think of it like...
Test functions are like recipe taste tests: after cooking a dish, you try a bite to make sure it tastes right before serving it to guests.
┌───────────────┐
│  Test Runner  │
└──────┬────────┘
       │ runs
┌──────▼────────┐
│ Test Function │
│  (test_xyz)   │
└──────┬────────┘
       │ asserts
┌──────▼────────┐
│  Code Output  │
│  vs Expected  │
└───────────────┘
Build-Up - 7 Steps
1
FoundationWriting Your First Test Function
🤔
Concept: Learn how to write a simple test function using pytest naming rules and assertions.
Create a Python file named test_sample.py. Write a function starting with 'test_' like test_addition(). Inside, use assert to check if 2 + 2 equals 4. Run pytest in the terminal to see the test pass.
Result
pytest runs the test and shows '1 passed' indicating the code works as expected.
Understanding the naming and assertion basics is key to making pytest recognize and run your tests automatically.
2
FoundationUsing Assertions to Check Results
🤔
Concept: Assertions compare actual results with expected values to confirm correctness.
Inside a test function, use assert statements like assert function_call() == expected_value. If the assertion fails, pytest reports an error showing what was expected and what was received.
Result
When assertion passes, test passes silently; when it fails, pytest shows a clear error message.
Assertions are the heart of test functions; they express what your code should do in a simple, readable way.
3
IntermediateOrganizing Multiple Test Functions
🤔Before reading on: do you think pytest runs tests in the order they appear or in a random order? Commit to your answer.
Concept: Learn how pytest discovers and runs multiple test functions in a file and across files.
Write several test functions in one file, each testing different parts of your code. Pytest finds all functions starting with 'test_' and runs them independently. The order is not guaranteed, so tests should not depend on each other.
Result
Pytest runs all tests and reports which pass or fail, regardless of their order.
Knowing that tests run independently helps you write reliable tests that don't interfere with each other.
4
IntermediateHandling Expected Failures Gracefully
🤔Before reading on: do you think a test that is expected to fail should be marked or just left as is? Commit to your answer.
Concept: Pytest allows marking tests that are expected to fail to keep track without breaking the test suite.
Use the @pytest.mark.xfail decorator above a test function that is known to fail due to a bug or unimplemented feature. Pytest will report it as an expected failure, not a test error.
Result
Tests marked xfail show as 'expected fail' in reports, keeping the suite clean while tracking issues.
Marking expected failures helps manage work-in-progress code and prevents noise in test results.
5
IntermediateUsing Setup Code Inside Test Functions
🤔
Concept: Sometimes tests need preparation steps before assertions, done inside the test function.
Inside a test function, create variables or call setup functions to prepare data or state. Then perform assertions on the prepared setup. This keeps tests self-contained and clear.
Result
Tests run with their own setup, making them independent and easier to understand.
Including setup inside tests avoids hidden dependencies and makes debugging easier.
6
AdvancedAvoiding Test Interdependence Pitfalls
🤔Before reading on: do you think tests that share data or state can cause hidden bugs? Commit to your answer.
Concept: Tests should be independent; sharing state can cause flaky or misleading results.
If one test modifies shared data, another test might fail unexpectedly. Use fresh data or pytest fixtures to isolate tests. Avoid global variables or shared mutable objects.
Result
Tests become reliable and repeatable, passing or failing only due to their own code.
Understanding test independence prevents hard-to-find bugs and builds trust in test results.
7
ExpertHow Pytest Discovers and Runs Test Functions
🤔Before reading on: do you think pytest uses file names, function names, or both to find tests? Commit to your answer.
Concept: Pytest uses naming conventions and internal hooks to find and run test functions efficiently.
Pytest looks for files named test_*.py or *_test.py, then inside those files finds functions starting with 'test_'. It collects these and runs them in isolated environments, capturing output and exceptions. Plugins can extend discovery and execution.
Result
Tests run automatically without manual registration, with detailed reports and support for advanced features.
Knowing pytest's discovery mechanism helps write tests that integrate smoothly and leverage pytest's power.
Under the Hood
Pytest scans your project folders for files matching test naming patterns. It imports these files as modules and inspects their contents for functions starting with 'test_'. Each test function runs in isolation, with pytest capturing exceptions and assertion failures. It uses Python's assert rewriting to provide detailed error messages. Test results are collected and summarized in a report.
Why designed this way?
Pytest was designed for simplicity and power. Using naming conventions avoids complex configuration. Running tests as simple functions lowers the barrier for beginners. Isolating tests prevents side effects. The assert rewriting feature was added to give clear feedback without extra code. This design balances ease of use with advanced capabilities.
Project Folder
  ├─ test_example.py
  │    ├─ test_func1()
  │    └─ test_func2()
  └─ test_utils.py
       └─ test_func3()

Pytest Discovery
  └─ Finds test files and functions

Test Execution
  ├─ Runs test_func1()
  ├─ Runs test_func2()
  └─ Runs test_func3()

Result Collection
  └─ Aggregates pass/fail info

Report Generation
  └─ Displays summary to user
Myth Busters - 4 Common Misconceptions
Quick: Do you think a test function must return a value to be valid? Commit to yes or no before reading on.
Common Belief:Test functions must return True or False to indicate pass or fail.
Tap to reveal reality
Reality:Test functions do not return anything; they use assertions to signal failure by raising exceptions. If no assertion fails, the test passes.
Why it matters:Expecting return values can confuse beginners and lead to incorrect test writing, causing tests to be ignored or misinterpreted.
Quick: Do you think tests should depend on each other to save time? Commit to yes or no before reading on.
Common Belief:Tests can rely on previous tests to set up data or state to avoid repetition.
Tap to reveal reality
Reality:Tests should be independent and self-contained. Dependencies cause flaky tests and make debugging hard.
Why it matters:Dependent tests can pass or fail unpredictably, hiding real bugs and wasting developer time.
Quick: Do you think pytest runs tests in the order they appear in the file? Commit to yes or no before reading on.
Common Belief:Pytest runs tests in the order they are written in the file.
Tap to reveal reality
Reality:Pytest does not guarantee test order; tests may run in any order or even in parallel.
Why it matters:Assuming order can cause hidden bugs if tests rely on side effects from previous tests.
Quick: Do you think a failing assertion always means your code is wrong? Commit to yes or no before reading on.
Common Belief:If a test assertion fails, the code under test is definitely broken.
Tap to reveal reality
Reality:A failing test can also mean the test itself is incorrect or outdated.
Why it matters:Blindly trusting failing tests can waste time chasing non-existent bugs or ignoring real issues.
Expert Zone
1
Pytest's assert rewriting transforms simple assert statements into rich error messages without extra code.
2
Test functions can be dynamically generated or parameterized to cover many cases with minimal code duplication.
3
Pytest supports fixtures that inject setup and teardown logic, keeping test functions clean and focused.
When NOT to use
Test functions are not suitable for testing asynchronous code without async support; use pytest-asyncio or similar plugins instead. For UI testing, use specialized tools like Selenium or Playwright. For performance testing, use dedicated profiling tools rather than simple test functions.
Production Patterns
In real projects, test functions are grouped into modules and folders by feature. They use fixtures for setup, parameterization for coverage, and markers to categorize tests (e.g., slow, integration). Continuous integration systems run these tests automatically on code changes.
Connections
Unit Testing
Test functions are the basic building blocks of unit testing.
Understanding test functions clarifies how unit tests isolate and verify small code parts.
Continuous Integration (CI)
Test functions run automatically in CI pipelines to catch bugs early.
Knowing test functions helps grasp how automated testing fits into modern software delivery.
Scientific Method
Test functions embody hypothesis testing by checking if code behaves as expected.
Seeing tests as experiments helps appreciate their role in validating assumptions and learning from failures.
Common Pitfalls
#1Writing test functions that depend on each other's side effects.
Wrong approach:def test_a(): global shared shared = 5 def test_b(): assert shared == 5
Correct approach:def test_a(): value = 5 assert value == 5 def test_b(): value = 5 assert value == 5
Root cause:Misunderstanding that tests run independently and should not share or rely on global state.
#2Using print statements instead of assertions to check results.
Wrong approach:def test_sum(): print(2 + 2 == 4)
Correct approach:def test_sum(): assert 2 + 2 == 4
Root cause:Confusing output for verification; tests must use assertions to signal pass/fail.
#3Naming test functions without the 'test_' prefix so pytest ignores them.
Wrong approach:def check_addition(): assert 1 + 1 == 2
Correct approach:def test_addition(): assert 1 + 1 == 2
Root cause:Not following pytest naming conventions prevents test discovery.
Key Takeaways
Test functions are simple Python functions named with 'test_' that use assertions to check code correctness.
Pytest automatically finds and runs test functions, reporting clear pass or fail results.
Tests must be independent, self-contained, and use assertions, not print statements or return values.
Understanding pytest's discovery and execution helps write effective and reliable tests.
Marking expected failures and organizing tests properly improves test suite maintenance and clarity.