CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-mock

Rolling backport of unittest.mock for all Pythons

Pending
Overview
Eval results
Files

utilities.mddocs/

Utilities

The mock library provides several utility functions for creating specialized mocks and managing mock behavior in advanced testing scenarios.

Capabilities

create_autospec

Automatically create a mock with the same specification as another object, preserving function signatures and type information.

def create_autospec(
    spec,
    spec_set=False,
    instance=False,
    _parent=None,
    _name=None,
    *,
    unsafe=False,
    **kwargs
):
    """
    Create a mock object with automatic specification from another object.
    
    Parameters:
    - spec: Object to create specification from
    - spec_set: If True, only attributes on spec can be set
    - instance: If True, mock represents instance of spec rather than spec itself
    - unsafe: Allow access to dangerous attributes
    - **kwargs: Additional arguments passed to mock constructor
    
    Returns:
    Mock object with same interface as spec
    
    The returned mock has the same signature as the original and will raise
    TypeError if called with wrong arguments. Attributes and methods are
    recursively auto-specced.
    """

mock_open

Create a mock for the built-in open() function, useful for testing file operations without actual file I/O.

def mock_open(mock=None, read_data=''):
    """
    Create a mock for the built-in open() function.
    
    Parameters:
    - mock: Mock to configure (defaults to MagicMock)
    - read_data: String data to return when file is read
    
    Returns:
    Mock object that behaves like built-in open()
    
    The mock supports context manager protocol and file-like operations.
    read(), readline(), and readlines() return data from read_data.
    """

seal

Seal a mock to prevent creation of new attributes, useful for catching typos and ensuring test isolation.

def seal(mock):
    """
    Seal a mock to prevent creation of new attributes.
    
    Parameters:
    - mock: Mock object to seal
    
    After sealing, accessing any new attributes will raise AttributeError.
    Existing attributes and their children are also sealed recursively.
    """

Usage Patterns

Using create_autospec

from mock import create_autospec

class RealClass:
    def method(self, arg1, arg2, kwarg=None):
        return 'real result'
    
    @property
    def prop(self):
        return 'real property'

# Create autospec mock
mock_obj = create_autospec(RealClass)

# Mock has same signature - this works
mock_obj.method('a', 'b', kwarg='c')

# This raises TypeError - wrong signature
try:
    mock_obj.method('too', 'many', 'args', 'here')
except TypeError:
    print("Caught signature mismatch")

# Configure return values
mock_obj.method.return_value = 'mocked result'
result = mock_obj.method('a', 'b')
assert result == 'mocked result'

# Properties work too
mock_obj.prop = 'mocked property'
assert mock_obj.prop == 'mocked property'

Instance vs Class Autospec

from mock import create_autospec

class MyClass:
    def __init__(self, value):
        self.value = value
    
    def method(self):
        return self.value

# Mock the class itself
MockClass = create_autospec(MyClass)
instance = MockClass('test')  # Returns mock instance
instance.method.return_value = 'mocked'

# Mock an instance of the class
mock_instance = create_autospec(MyClass, instance=True)
mock_instance.method.return_value = 'mocked'
# mock_instance('arg')  # Would raise TypeError - instances aren't callable

Using mock_open

from mock import mock_open, patch

# Basic file reading
m = mock_open(read_data='file contents')
with patch('builtins.open', m):
    with open('filename', 'r') as f:
        data = f.read()
    assert data == 'file contents'

# Mock file operations
m = mock_open()
with patch('builtins.open', m):
    with open('filename', 'w') as f:
        f.write('test data')
    
    # Verify file was opened and written to
    m.assert_called_once_with('filename', 'w')
    handle = m()
    handle.write.assert_called_once_with('test data')

# Multiple reads
m = mock_open(read_data='line1\nline2\nline3')
with patch('builtins.open', m):
    with open('filename', 'r') as f:
        lines = f.readlines()
    assert lines == ['line1\n', 'line2\n', 'line3']

File-like Object Operations

from mock import mock_open, patch

# Test reading line by line
m = mock_open(read_data='line1\nline2\nline3')
with patch('builtins.open', m):
    with open('filename', 'r') as f:
        first_line = f.readline()
        remaining = f.read()
    
    assert first_line == 'line1\n'
    assert remaining == 'line2\nline3'

# Test iteration
m = mock_open(read_data='line1\nline2\nline3')
with patch('builtins.open', m):
    with open('filename', 'r') as f:
        lines = list(f)
    
    assert lines == ['line1\n', 'line2\n', 'line3']

Using seal

from mock import Mock, seal

# Create and configure mock
mock_obj = Mock()
mock_obj.existing_attr = 'value'
mock_obj.method.return_value = 'result'

# Seal the mock
seal(mock_obj)

# Existing attributes still work
assert mock_obj.existing_attr == 'value'
assert mock_obj.method() == 'result'

# New attributes raise AttributeError
try:
    _ = mock_obj.new_attr  # This will raise AttributeError
except AttributeError:
    print("Caught access to new attribute")

try:
    mock_obj.new_attr = 'value'  # This will also raise AttributeError  
except AttributeError:
    print("Caught setting new attribute")

Comprehensive File Testing

from mock import mock_open, patch, call

def read_and_process_file(filename):
    """Function that reads a file and processes its contents."""
    with open(filename, 'r') as f:
        data = f.read()
    
    # Process data somehow
    processed = data.upper()
    
    # Write result back
    with open(filename + '.processed', 'w') as f:
        f.write(processed)
    
    return processed

# Test the function
m = mock_open(read_data='hello world')
with patch('builtins.open', m):
    result = read_and_process_file('test.txt')
    
    # Verify result
    assert result == 'HELLO WORLD'
    
    # Verify file operations
    expected_calls = [
        call('test.txt', 'r'),
        call().__enter__(),
        call().read(),
        call().__exit__(None, None, None),
        call('test.txt.processed', 'w'),
        call().__enter__(),
        call().write('HELLO WORLD'),
        call().__exit__(None, None, None)
    ]
    m.assert_has_calls(expected_calls)

Autospec with Wrapping

from mock import create_autospec

class Calculator:
    def add(self, a, b):
        return a + b
    
    def multiply(self, a, b):
        return a * b

real_calc = Calculator()

# Create autospec that wraps real object
mock_calc = create_autospec(Calculator, wrap=real_calc)

# Calls pass through to real object
result = mock_calc.add(2, 3)
assert result == 5  # Real calculation happened

# But we can still verify calls were made
mock_calc.add.assert_called_with(2, 3)

# And override specific methods when needed
mock_calc.multiply.return_value = 999
result = mock_calc.multiply(2, 3)
assert result == 999  # Mocked value, not real calculation

Install with Tessl CLI

npx tessl i tessl/pypi-mock

docs

index.md

mock-objects.md

patching.md

special-objects.md

utilities.md

tile.json