Sorry for the rather confusing title, but find it really hard to get to a crisp headline.
My Problem:
I have a submodule under test lets call it backend
. And I use random.choice
in backend
. I patch it in my test and that works. It is patched. backend
imports pymongo
to do some database stuff and pymongo uses random.choice
as well for selecting the right server in core.py
.
Somehow my patch of backend.random.choice
also is used for backend.pymongo.random.choice
. I am not sure why. Is that the correct behavior? And if it is, what is the way to get around that? Preferebly without changing any code in backend and pymongo, but only in my tests.
Other investigation:
I set up a little test construct to see if that is something related to my project or a general thing.
I created some modules:
bar/bar.py
import random
def do_some_other_something():
return random.choice([10])
foo/foo.py
import random
from bar.bar import do_some_other_something
def do_something():
return random.choice([1])
def do_something_else():
return do_some_other_something()
And a test case:
from foo.foo import do_something, do_something_else
from unittest import mock
assert(do_something() == 1) # check
assert(do_something_else() == 10) # check
with mock.patch("foo.foo.random.choice") as mock_random_choice:
assert (do_something() != 1) # check (mocked as expected)
assert (do_something_else() == 10) # assertion! also mocked
So I am really confused about this. I explicitly mocked foo.foo's random.choice not bar.bar's. So why is that happening? Intended? Is there a way to fix that?
Thank you!
There's only one random
module in the program. When foo.foo
and bar.bar
both import random
, they share the random
module. Patching the choice
function on the random
module modifies the one random
module used by every part of the program, including both foo.foo
and bar.bar
.
Instead of patching foo.foo.random.choice
, patch foo.foo.random
. That replaces foo.foo
's reference to the random
module, but not bar.bar
's reference. bar.bar
will continue to access the real random
module, but foo.foo
will see a mock random
.