I'm not sure if static vs. dynamic mock is the terminology used to describe this comparison, but I got this terminology from types of mocking static vs dynamic and Hand-rolled mocks made easy. To summarize, a dynamic mock is a proxy generated on the fly, whereas a static mock is pre-implemented. For a Python example given this abstract
Value domain object and example
class Value: ... class Repository(ABC): @abstractmethod def read_value(value_id: str) -> Value: pass class DatabaseRepository(Repository): def __init__(self): self.database_client = ... def read_value(value_id: str) -> Value: # Use `self.database_client` and `value_id` to fetch a parsable `Value`. ...
A static mock would look like:
from abc import ABC, abstractmethod class MockRepository(Repository): def read_value(_: str) -> Value: return Value(...) # Ignores `value_id` and returns predefined `Value` for mocking purpose. static_mock = MockRepository()
A dynamic mock would look like:
from unittest.mock import Mock dynamic_mock = Mock(spec=Repository) dynamic_mock.read_value.return_value = Value(...)
In the code bases I've worked with, I've rarely seen the static mock. Yet the static mock seems to come with numerous benefits, a major one being compile-time safely for constructing the mock object in a statically typed language (or in Python, safety that can enforced by a type checker like
The only benefit to dynamic mocks seems to be the conciseness (also mentioned by the two links), and while this is a valid benefit, is there anything I'm missing in regards to what a dynamic mock can do exclusively or more naturally compared to a static mock? Does design of a particular language (like statically typed vs. dynamically typed) tilt this comparison scale?
What you have here is a stub. Stubs are used to inject values into other objects. These values can be used to take the execution down different logical paths in the function under test. Return true, return false, throw exception.
Creating stubs dynamically (considered configurable stubs) just keeps the code base clean and reduces the need to manage large amounts of helper classes. Hard-coded stubs are custom built for one test, so you can imagine how that would go with a code base with 1000 of tests. Soon as the test suite gets bigger the management of hard coded stubs gets problematic.
Mocks are different. They remember how they were used and that can be verified as part of the test; i.e. the SaveToDatabase() method was called three times.
There is a fantastic book called xUnit Test Patterns that contains everything you need to know about this topic. It's really good and shouldn't be too difficult to find.
dynamic_mockis actually a configurable stub right now even though it's instantiated as
Mock, but if I asserted that it/one of its methods was used X number of times then it would be considered a mock? — Sep 02, 2020 at 15:53
External links referenced by this document: