Thin-wrapper around the mock package for easier use with pytest
—
pytest-mock provides MockerFixture instances through pytest fixtures at multiple scopes, enabling flexible mock management across different test organization patterns. Each fixture provides the same MockerFixture interface but with different lifetimes and cleanup behaviors.
The default mocker fixture provides a MockerFixture instance that's created fresh for each test function and automatically cleaned up afterwards.
@pytest.fixture
def mocker(pytestconfig) -> Generator[MockerFixture, None, None]:
"""
Function-scoped mocker fixture (default scope).
Creates a new MockerFixture instance for each test function.
All mocks are automatically stopped after the test completes.
Yields:
MockerFixture instance for the test function
"""Usage examples:
def test_function_scope_basic(mocker):
# Fresh mocker instance for this test
mock_func = mocker.patch('os.path.exists')
mock_func.return_value = True
result = check_file_exists('test.txt')
assert result is True
mock_func.assert_called_once_with('test.txt')
# Mock automatically cleaned up after test
def test_function_scope_independent(mocker):
# Completely independent mocker instance
mock_func = mocker.patch('os.path.exists')
mock_func.return_value = False
result = check_file_exists('other.txt')
assert result is False
# No interference from previous test
class TestWithFunctionScope:
def test_method_one(self, mocker):
# Fresh mocker for this method
spy = mocker.spy(Calculator, 'add')
calc = Calculator()
result = calc.add(2, 3)
spy.assert_called_once_with(2, 3)
def test_method_two(self, mocker):
# Independent mocker instance
mock_calc = mocker.create_autospec(Calculator)
mock_calc.add.return_value = 100
assert mock_calc.add(1, 1) == 100The class_mocker fixture provides a MockerFixture instance shared across all test methods in a test class, with cleanup after the class completes.
@pytest.fixture(scope="class")
def class_mocker(pytestconfig) -> Generator[MockerFixture, None, None]:
"""
Class-scoped mocker fixture.
Creates one MockerFixture instance shared by all test methods
in a test class. Mocks persist across methods and are cleaned
up after the class completes.
Yields:
MockerFixture instance for the test class
"""Usage examples:
class TestDatabaseOperations:
def test_connection_setup(self, class_mocker):
# Mock persists for entire class
self.db_mock = class_mocker.patch('myapp.database.connect')
self.db_mock.return_value = 'mock_connection'
setup_database()
self.db_mock.assert_called_once()
def test_query_execution(self, class_mocker):
# Same mocker instance, mocks still active
query_mock = class_mocker.patch('myapp.database.execute_query')
query_mock.return_value = [{'id': 1, 'name': 'test'}]
results = run_query('SELECT * FROM users')
# db_mock from previous test is still active
assert self.db_mock.called
query_mock.assert_called_once()
assert len(results) == 1
def test_connection_cleanup(self, class_mocker):
# All mocks from class still available
cleanup_mock = class_mocker.patch('myapp.database.disconnect')
cleanup_database()
# Can verify interactions across the whole class
assert self.db_mock.call_count >= 1
cleanup_mock.assert_called_once()
# All mocks automatically cleaned up after class completes
# Different class gets fresh mocker instance
class TestFileOperations:
def test_independent_mocking(self, class_mocker):
# Completely separate from TestDatabaseOperations
file_mock = class_mocker.patch('builtins.open')
file_mock.return_value.__enter__.return_value.read.return_value = 'content'
data = read_file('test.txt')
assert data == 'content'The module_mocker fixture provides a MockerFixture instance shared across all tests in a module, with cleanup after the module completes.
@pytest.fixture(scope="module")
def module_mocker(pytestconfig) -> Generator[MockerFixture, None, None]:
"""
Module-scoped mocker fixture.
Creates one MockerFixture instance shared by all tests
in a module. Mocks persist across functions and classes
and are cleaned up after the module completes.
Yields:
MockerFixture instance for the test module
"""Usage examples:
# test_api_integration.py
# Module-level setup with module_mocker
@pytest.fixture(scope="module", autouse=True)
def setup_api_mocks(module_mocker):
"""Setup common mocks for entire module."""
# Mock external API calls for all tests in module
module_mocker.patch('requests.get', side_effect=mock_api_response)
module_mocker.patch('requests.post', side_effect=mock_api_post)
# Mock authentication for all tests
auth_mock = module_mocker.patch('myapp.auth.verify_token')
auth_mock.return_value = True
return module_mocker
def test_get_user_data(module_mocker):
# Uses module-level mocks automatically
user_data = fetch_user_data(user_id=123)
# Can add test-specific mocks too
cache_mock = module_mocker.patch('myapp.cache.get')
cached_data = get_cached_user(user_id=123)
assert user_data['id'] == 123
cache_mock.assert_called_once()
def test_create_user(module_mocker):
# Same module-level mocks still active
new_user = create_user({'name': 'Test User'})
# requests.post mock from setup is used
assert new_user['status'] == 'created'
class TestUserManagement:
def test_update_user(self, module_mocker):
# Module-level mocks available in classes too
result = update_user(123, {'name': 'Updated'})
assert result['success'] is True
def test_delete_user(self, module_mocker):
# All module mocks persist across class methods
result = delete_user(123)
assert result['deleted'] is True
# All module-level mocks cleaned up when module completesThe package_mocker fixture provides a MockerFixture instance shared across all tests in a Python package, with cleanup after the package completes.
@pytest.fixture(scope="package")
def package_mocker(pytestconfig) -> Generator[MockerFixture, None, None]:
"""
Package-scoped mocker fixture.
Creates one MockerFixture instance shared by all tests
in a package. Mocks persist across modules and are
cleaned up after the package completes.
Yields:
MockerFixture instance for the test package
"""Usage examples:
# tests/conftest.py - Package-level configuration
@pytest.fixture(scope="package", autouse=True)
def package_setup(package_mocker):
"""Setup package-wide mocks and configuration."""
# Mock external services for entire test package
package_mocker.patch('myapp.external.payment_service.charge')
package_mocker.patch('myapp.external.email_service.send')
# Mock environment configuration
package_mocker.patch.dict('os.environ', {
'DATABASE_URL': 'sqlite:///:memory:',
'REDIS_URL': 'redis://localhost:6379/15',
'API_KEY': 'test-api-key'
})
return package_mocker
# tests/test_payments.py
def test_process_payment(package_mocker):
# Uses package-level payment service mock
result = process_payment(amount=100, card_token='tok_123')
assert result['status'] == 'success'
# tests/test_notifications.py
def test_send_notification(package_mocker):
# Uses package-level email service mock
send_welcome_email('user@example.com')
# Email mock is already configured at package level
# tests/integration/test_workflows.py
def test_complete_workflow(package_mocker):
# All package-level mocks available in subdirectories
workflow = CompleteUserWorkflow()
result = workflow.execute(user_data={'email': 'test@example.com'})
# Payment and email mocks from package level are used
assert result['payment_processed'] is True
assert result['welcome_sent'] is TrueThe session_mocker fixture provides a MockerFixture instance shared across the entire test session, with cleanup after all tests complete.
@pytest.fixture(scope="session")
def session_mocker(pytestconfig) -> Generator[MockerFixture, None, None]:
"""
Session-scoped mocker fixture.
Creates one MockerFixture instance shared by all tests
in the session. Mocks persist across all packages and
modules and are cleaned up after the session completes.
Yields:
MockerFixture instance for the test session
"""Usage examples:
# conftest.py at root of test suite
@pytest.fixture(scope="session", autouse=True)
def global_test_setup(session_mocker):
"""Setup session-wide mocks for external dependencies."""
# Mock third-party services for entire test session
session_mocker.patch('stripe.api_resources.Charge.create')
session_mocker.patch('boto3.client') # Mock AWS services
session_mocker.patch('redis.Redis.from_url')
# Mock time-based functions for consistent testing
import datetime
fixed_time = datetime.datetime(2023, 1, 1, 12, 0, 0)
session_mocker.patch('datetime.datetime.now', return_value=fixed_time)
return session_mocker
# Any test file in the session
def test_stripe_integration(session_mocker):
# Uses session-level stripe mock automatically
charge = create_payment_charge(amount=1000)
assert charge['status'] == 'succeeded'
def test_aws_s3_upload(session_mocker):
# Uses session-level boto3 mock automatically
result = upload_file_to_s3('test.txt', 'content')
assert result['success'] is True
# Different package, same session mocks
def test_redis_caching(session_mocker):
# Uses session-level redis mock automatically
cache_key = 'test:key'
set_cache(cache_key, 'value')
value = get_cache(cache_key)
assert value == 'value'
def test_time_dependent_logic(session_mocker):
# Uses session-level datetime mock - consistent time across all tests
timestamp = get_current_timestamp()
assert timestamp == '2023-01-01T12:00:00'# Scope lifecycles and use cases
def test_scope_demonstration():
"""
Fixture Scopes (from shortest to longest lived):
1. function (default) - New MockerFixture per test function
- Use for: Isolated test mocks, no shared state needed
- Cleanup: After each test function
2. class - One MockerFixture per test class
- Use for: Shared setup within related test methods
- Cleanup: After test class completes
3. module - One MockerFixture per test module
- Use for: Expensive mocks, module-wide configuration
- Cleanup: After test module completes
4. package - One MockerFixture per test package
- Use for: Package-wide external service mocks
- Cleanup: After test package completes
5. session - One MockerFixture for entire test session
- Use for: Global mocks, third-party service mocks
- Cleanup: After all tests complete
"""
# Choosing the right scope:
def test_choosing_fixture_scope():
"""
Guidelines for fixture scope selection:
- function: Default choice, ensures test isolation
- class: When test methods need shared mock state
- module: For expensive-to-create mocks used across module
- package: For mocking external dependencies across packages
- session: For global mocks that should never change
Trade-offs:
- Longer scopes = better performance, less isolation
- Shorter scopes = better isolation, more setup overhead
"""Install with Tessl CLI
npx tessl i tessl/pypi-pytest-mock