Python - Mocking and Stubbing



Python mocking and stubbing are important techniques in unit testing that help to isolate the functionality being tested by replacing real objects or methods with controlled substitutes. In this chapter we are going to understand about Mocking and Stubbing in detail −

Python Mocking

Mocking is a testing technique in which mock objects are created to simulate the behavior of real objects.

This is useful when testing a piece of code that interacts with complex, unpredictable or slow components such as databases, web services or hardware devices.

The primary purpose of mocking is to isolate the code under test and ensure that its behavior is evaluated independently of its dependencies.

Key Characteristics of Mocking

The following are the key characteristics of mocking in python −

  • Behavior Simulation: Mock objects can be programmed to return specific values, raise exceptions or mimic the behavior of real objects under various conditions.
  • Interaction Verification: Mocks can record how they were used by allowing the tester to verify that specific methods were called with the expected arguments.
  • Test Isolation:By replacing real objects with mocks, tests can focus on the logic of the code under test without worrying about the complexities or availability of external dependencies.

Example of Python Mocking

Following is the example of the database.get_user method, which is mocked to return a predefined user dictionary. The test can then verify that the method was called with the correct arguments −

from unittest.mock import Mock

# Create a mock object
database = Mock()

# Simulate a method call
database.get_user.return_value = {"name": "Prasad", "age": 30}

# Use the mock object
user = database.get_user("prasad_id")
print(user)  

# Verify the interaction
database.get_user.assert_called_with("prasad_id") 

Output

{'name': 'Prasad', 'age': 30}

Python Stubbing

Stubbing is a related testing technique where certain methods or functions are replaced with "stubs" that return fixed, predetermined responses.

Stubbing is simpler than mocking because it typically does not involve recording or verifying interactions. Instead, stubbing focuses on providing controlled inputs to the code under test by ensuring consistent and repeatable results.

Key Characteristics of Stubbing

The following are the key characteristics of Stubbing in python −

  • Fixed Responses: Stubs return specific, predefined values or responses regardless of how they are called.
  • Simplified Dependencies: By replacing complex methods with stubs, tests can avoid the need to set up or manage intricate dependencies.
  • Focus on Inputs: Stubbing emphasizes providing known inputs to the code under test by allowing the tester to focus on the logic and output of the tested code.

Example of Python Stubbing

Following is the example of the get_user_from_db function, which is stubbed to always return a predefined user dictionary. The test does not need to interact with a real database for simplifying the setup and ensuring consistent results −

from unittest.mock import 

# Define the function to be stubbed
def get_user_from_db(user_id):
   # Simulate a complex database operation
   pass

# Test the function with a stub
with ('__main__.get_user_from_db', return_value={"name": "Prasad", "age": 25}):
   user = get_user_from_db("prasad_id")
   print(user)  

Output

{'name': 'Prasad', 'age': 25}

Python Mocking Vs. Stubbing

The comparison of the Mocking and Stubbing key features, purposes and use cases gives the clarity on when to use each method. By exploring these distinctions, developers can create more effective and maintainable tests which ultimately leads to higher quality software.

The following table shows the key difference between mocking and stubbing based on the different criteria −

CriteriaMockingStubbing
PurposeSimulate the behavior of real objectsProvide fixed, predetermined responses
Interaction VerificationCan verify method calls and argumentsTypically does not verify interactions
ComplexityMore complex; can simulate various behaviorsSimpler; focuses on providing controlled inputs
Use CaseIsolate and test code with complex dependenciesSimplify tests by providing known responses
Recording BehaviorRecords how methods were calledDoes not record interactions
State ManagementCan maintain state across callsUsually stateless; returns fixed output
Framework SupportPrimarily uses unittest.mock with features like Mock and MagicMockUses unittest.mock's for simple replacements
FlexibilityHighly flexible; can simulate exceptions and side effectsLimited flexibility; focused on return values