I have the following (simplified) piece of code:
def get_redis()
return redis_instance
def bar(key, value, redis=get_redis())
redis.set(key, value)
def foo()
bar("key", value)
In my test I want to mock the function get_redis
to return an instance of fakeredis.FakeStrictRedis()
, so I did this
def test_foo(mocker):
mocker.patch("app.main.get_redis", return_value=fakeredis.FakeStrictRedis())
foo()
the mocked function has no effect, the foo
function try to connect to real redis using the get_redis function from main.
If I wrote in this way works
def bar(key, value)
redis=get_redis()
redis.set(key, value)
This works, but I can pass redis as default value. How can I mock?
2
Answers
I would just modify the
bar
function slightly as follows so that your functions don’t get called before the mock can be applied:Writing the function this way means that your mock will apply at the time the function is called, and not at startup before any mocks can be applied. In short, writing
bar
this way, ensures the return ofget_redis
it will propagate through yourbar
function every time the function is called .There’s nothing wrong with your mock, but you seem to be misunderstanding how default parameter values work. As explained in the Python Language Reference, default parameter values are evaluated when the function definition is executed.
In your case, this means that the original
get_redis
is called already whenbar
is defined:This statement is executed when
pytest
imports your module, i.e., beforetest_foo
is executed, so mockingget_redis
in the test has no effect because it’s already too late by then.To make the default-supplying factory function mockable, use
None
as the default and make the function call the factory unless another value was specified in the call: