Test discovery rules in PyTest - Build an Automation Script
import pytest import os import subprocess import sys def write_file(filename: str, content: str): with open(filename, 'w') as f: f.write(content) def test_pytest_discovery(tmp_path): # Create test_sample.py with two test functions test_sample_content = ''' def test_addition(): assert 1 + 1 == 2 def test_subtraction(): assert 2 - 1 == 1 ''' write_file(tmp_path / 'test_sample.py', test_sample_content) # Create sample_test.py with one test function sample_test_content = ''' def test_multiplication(): assert 2 * 3 == 6 ''' write_file(tmp_path / 'sample_test.py', sample_test_content) # Create sample.py with a function named test_division (not a test file) sample_content = ''' def test_division(): assert 6 / 2 == 3 ''' write_file(tmp_path / 'sample.py', sample_content) # Run pytest in the tmp_path directory result = subprocess.run( [sys.executable, '-m', 'pytest', '--collect-only', '-q'], cwd=tmp_path, capture_output=True, text=True ) # The output lists collected tests by their node ids collected_tests = result.stdout.strip().split('\n') # We expect exactly 3 tests collected assert len(collected_tests) == 3, f"Expected 3 tests collected, got {len(collected_tests)}" # Check that the collected tests are the expected ones expected_tests = { 'test_sample.py::test_addition', 'test_sample.py::test_subtraction', 'sample_test.py::test_multiplication' } assert set(collected_tests) == expected_tests, f"Collected tests do not match expected. Got: {collected_tests}" # Run pytest normally and capture output run_result = subprocess.run( [sys.executable, '-m', 'pytest', '-q', '--tb=no'], cwd=tmp_path, capture_output=True, text=True ) # Check that the output contains the names of the three tests run for test_name in ['test_addition', 'test_subtraction', 'test_multiplication']: assert test_name in run_result.stdout, f"{test_name} not found in pytest output" # Check that test_division is not run assert 'test_division' not in run_result.stdout, "test_division should not be run because file name does not match discovery rules"
This test script uses pytest and Python's subprocess module to verify pytest's test discovery rules.
First, it creates three Python files in a temporary directory:
test_sample.pywith two test functions.sample_test.pywith one test function.sample.pywith a function named like a test but in a non-test file.
Then, it runs pytest --collect-only to list all discovered tests and asserts that only the three functions in the correctly named test files are collected.
Next, it runs pytest normally to execute the tests and checks the output to confirm the expected tests ran and the function in sample.py did not run.
This approach ensures the test discovery rules are correctly followed by pytest.
Now add data-driven testing with 3 different inputs to one of the test functions using pytest parametrize
Practice
Solution
Step 1: Understand pytest file naming rules
pytest looks for files starting or ending with 'test' and ending with '.py'.Step 2: Check each option
'test_example.py' starts with 'test' and ends with '.py', so pytest will find it. Others either don't end with '.py' or don't start/end with 'test'.Final Answer:
test_example.py -> Option BQuick Check:
File starts or ends with 'test' + '.py' = test_example.py [OK]
- Thinking pytest finds .pyc files
- Ignoring case sensitivity in file names
- Assuming any .py file is a test file
Solution
Step 1: Recall pytest test function naming
pytest looks for functions starting with 'test_'.Step 2: Evaluate each function name
'test_login()' starts with 'test_' exactly, so pytest will find it. Others do not follow this pattern.Final Answer:
test_login() -> Option AQuick Check:
Function starts with 'test_' = test_login() [OK]
- Using camelCase instead of snake_case
- Placing 'test' at the end of function name
- Missing underscore after 'test'
File: test_math.py def test_add(): pass def add_test(): pass File: math_test.py def test_subtract(): pass def subtract_test(): pass File: math.py def test_multiply(): pass
Solution
Step 1: Identify test files pytest finds
pytest finds files starting or ending with 'test' and ending with '.py'. So 'test_math.py' and 'math_test.py' are test files. 'math.py' is not.Step 2: Identify test functions pytest finds in those files
In 'test_math.py', pytest finds 'test_add' (starts with 'test_'). 'add_test' is ignored. In 'math_test.py', pytest finds 'test_subtract'. 'subtract_test' is ignored. 'test_multiply' in 'math.py' is ignored because file is not a test file.Final Answer:
test_add, test_subtract -> Option AQuick Check:
Files and functions follow naming rules = test_add, test_subtract [OK]
- Assuming any function starting with 'test' is found regardless of file name
- Including functions in non-test files
- Confusing function name endings with beginnings
TestExample.py with a function def test_func():. pytest does not run this test. What is the likely cause?Solution
Step 1: Check pytest file discovery rules
pytest finds files starting or ending with 'test' in lowercase and ending with '.py'. 'TestExample.py' starts with uppercase 'T', so it is not recognized.Step 2: Verify function name and other options
Function name 'test_func' is correct. Return statement is not required. pytest does not require test classes to run functions.Final Answer:
File name does not follow pytest discovery rules -> Option CQuick Check:
File name case-sensitive for discovery = D [OK]
- Ignoring case sensitivity in file names
- Thinking function needs return statement
- Assuming test classes are mandatory
mytests.py containing functions def test_one(): and def test_two():. By default, pytest does not find this file. How can you rename the file to follow pytest discovery rules without changing function names?Solution
Step 1: Recall pytest file discovery naming
pytest finds files starting with 'test_' or ending with '_test.py'.Step 2: Check options for correct naming
'test_mytests.py' starts with 'test_' [check]. 'mytestsTest.py' ends with 'Test.py' (uppercase 'T' not matching lowercase 'test'). 'testmytests.py' lacks '_' after 'test'. 'my_test_s.py' does not start with 'test_' or end with '_test.py'. Only the first option works.Final Answer:
Rename to test_mytests.py -> Option DQuick Check:
File starts or ends with 'test' = test_mytests.py [OK]
- Removing 'test' from file name
- Adding 'test' inside word without underscore
- Using camelCase instead of snake_case
Ready to prove it?
Pass the test and this pattern moves unknown
