RedisPlugin Guide¶
RedisPlugin intercepts redis.Redis.execute_command at the class level. Unlike other stateful plugins, Redis commands carry no inherent ordering constraint, so RedisPlugin extends BasePlugin directly and uses a per-command FIFO queue rather than a session handle with state transitions.
Installation¶
This installs redis>=4.0.0.
Setup¶
In pytest, access RedisPlugin through the bigfoot.redis_mock proxy. It auto-creates the plugin for the current test on first use:
import bigfoot
def test_cache_lookup():
bigfoot.redis_mock.mock_command("GET", returns="cached_value")
with bigfoot:
import redis
r = redis.Redis()
value = r.execute_command("GET", "mykey")
assert value == "cached_value"
bigfoot.redis_mock.assert_command("GET", args=("mykey",), kwargs={})
For manual use outside pytest, construct RedisPlugin explicitly:
from bigfoot import StrictVerifier
from bigfoot.plugins.redis_plugin import RedisPlugin
verifier = StrictVerifier()
redis_mock = RedisPlugin(verifier)
Each verifier may have at most one RedisPlugin. A second RedisPlugin(verifier) raises ValueError.
Registering mock commands¶
Use bigfoot.redis_mock.mock_command(command, *, returns, ...) to register a mock before entering the sandbox:
bigfoot.redis_mock.mock_command("SET", returns=True)
bigfoot.redis_mock.mock_command("GET", returns="hello")
Parameters¶
| Parameter | Type | Default | Description |
|---|---|---|---|
command |
str |
required | Redis command name, case-insensitive |
returns |
Any |
required | Value to return when this mock is consumed |
raises |
BaseException \| None |
None |
Exception to raise instead of returning |
required |
bool |
True |
Whether an unused mock causes UnusedMocksError at teardown |
Per-command FIFO queues¶
Each command name has its own independent FIFO queue. Multiple mock_command("GET", ...) calls are consumed in registration order when GET is executed:
def test_multiple_gets():
bigfoot.redis_mock.mock_command("GET", returns="first")
bigfoot.redis_mock.mock_command("GET", returns="second")
with bigfoot:
r = redis.Redis()
v1 = r.execute_command("GET", "key1")
v2 = r.execute_command("GET", "key2")
assert v1 == "first"
assert v2 == "second"
bigfoot.redis_mock.assert_command("GET", args=("key1",), kwargs={})
bigfoot.redis_mock.assert_command("GET", args=("key2",), kwargs={})
Command names are case-insensitive: mock_command("get", ...) matches execute_command("GET", ...).
Asserting interactions¶
Use the assert_command helper on bigfoot.redis_mock. All three fields (command, args, kwargs) are required:
assert_command(command, args, kwargs)¶
| Parameter | Type | Default | Description |
|---|---|---|---|
command |
str |
required | Redis command name (automatically uppercased) |
args |
tuple |
() |
Positional arguments passed to execute_command after the command name |
kwargs |
dict \| None |
None |
Keyword arguments passed to execute_command (defaults to {}) |
Simulating errors¶
Use the raises parameter to simulate Redis errors:
import redis as redis_lib
import bigfoot
def test_redis_error():
bigfoot.redis_mock.mock_command(
"GET",
returns=None,
raises=redis_lib.exceptions.ResponseError("WRONGTYPE"),
)
with bigfoot:
r = redis.Redis()
with pytest.raises(redis_lib.exceptions.ResponseError):
r.execute_command("GET", "badkey")
bigfoot.redis_mock.assert_command("GET", args=("badkey",), kwargs={})
Full example¶
import redis
import bigfoot
def increment_counter(r, name):
current = r.execute_command("GET", name)
new_val = int(current or 0) + 1
r.execute_command("SET", name, str(new_val))
return new_val
def test_increment_counter():
bigfoot.redis_mock.mock_command("GET", returns="5")
bigfoot.redis_mock.mock_command("SET", returns=True)
with bigfoot:
r = redis.Redis()
result = increment_counter(r, "visits")
assert result == 6
bigfoot.redis_mock.assert_command("GET", args=("visits",), kwargs={})
bigfoot.redis_mock.assert_command("SET", args=("visits", "6"), kwargs={})
Optional mocks¶
Mark a mock as optional with required=False:
An optional mock that is never triggered does not cause UnusedMocksError at teardown.
UnmockedInteractionError¶
When code calls execute_command with a command that has no remaining mocks in its queue, bigfoot raises UnmockedInteractionError: