How to mock an import
You can assign to sys.modules['B']
before importing A
to get what you want:
test.py:
import syssys.modules['B'] = __import__('mock_B')import Aprint(A.B.__name__)
A.py:
import B
Note B.py does not exist, but when running test.py
no error is returned and print(A.B.__name__)
prints mock_B
. You still have to create a mock_B.py
where you mock B
's actual functions/variables/etc. Or you can just assign a Mock()
directly:
test.py:
import syssys.modules['B'] = Mock()import A
The builtin __import__
can be mocked with the 'mock' library for more control:
# Store original __import__orig_import = __import__# This will be the B moduleb_mock = mock.Mock()def import_mock(name, *args): if name == 'B': return b_mock return orig_import(name, *args)with mock.patch('__builtin__.__import__', side_effect=import_mock): import A
Say A
looks like:
import Bdef a(): return B.func()
A.a()
returns b_mock.func()
which can be mocked also.
b_mock.func.return_value = 'spam'A.a() # returns 'spam'
Note for Python 3:As stated in the changelog for 3.0, __builtin__
is now named builtins
:
Renamed module
__builtin__
tobuiltins
(removing the underscores, adding an āsā).
The code in this answer works fine if you replace __builtin__
by builtins
for Python 3.
How to mock an import, (mock A.B)?
Module A includes import B at its top.
Easy, just mock the library in sys.modules before it gets imported:
if wrong_platform(): sys.modules['B'] = mock.MagicMock()
and then, so long as A
doesn't rely on specific types of data being returned from B's objects:
import A
should just work.
You can also mock import A.B
:
This works even if you have submodules, but you'll want to mock each module. Say you have this:
from foo import This, That, andTheOtherThingfrom foo.bar import Yada, YadaYadafrom foo.baz import Blah, getBlah, boink
To mock, simply do the below before the module that contains the above is imported:
sys.modules['foo'] = MagicMock()sys.modules['foo.bar'] = MagicMock()sys.modules['foo.baz'] = MagicMock()
(My experience: I had a dependency that works on one platform, Windows, but didn't work on Linux, where we run our daily tests.So I needed to mock the dependency for our tests. Luckily it was a black box, so I didn't need to set up a lot of interaction.)
Mocking Side Effects
Addendum: Actually, I needed to simulate a side-effect that took some time. So I needed an object's method to sleep for a second. That would work like this:
sys.modules['foo'] = MagicMock()sys.modules['foo.bar'] = MagicMock()sys.modules['foo.baz'] = MagicMock()# setup the side-effect:from time import sleepdef sleep_one(*args): sleep(1)# this gives us the mock objects that will be usedfrom foo.bar import MyObject my_instance = MyObject()# mock the method!my_instance.method_that_takes_time = mock.MagicMock(side_effect=sleep_one)
And then the code takes some time to run, just like the real method.