How to mock import

Module A includes import B at its top. However, in test conditions, I would like to make fun of B in A (mock AB ) and completely refrain from importing B

In fact, B not specifically installed in the test environment.

A is the unit being checked. I have to import A with all its functions. B is the module I need for the layout. But how can I make fun of B inside A and stop A from importing real B if the first thing A does is import B ?

(The reason B is not installed is because I use pypy for quick testing, and unfortunately B is not yet compatible with pypy.)

How could this be done?

+121
python mocking python-import
Dec 28 '11 at 15:51
source share
7 answers

You can assign sys.modules['B'] before importing A to get what you want:

test.py

 import sys sys.modules['B'] = __import__('mock_B') import A print(AB__name__) 

A.py

 import B 

Note. B.py does not exist, but when test.py run test.py error does not return and print(AB__name__) prints mock_B . You still need to create mock_B.py where you mock the actual functions / variables of B, etc. Or you can simply assign Mock () directly:

test.py

 import sys sys.modules['B'] = Mock() import A 
+116
Dec 28 '11 at 16:13
source share

The built-in __import__ can be modeled using the 'mock' library for more control:

 # Store original __import__ orig_import = __import__ # This will be the B module b_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 

Let's say it looks like this: A

 import B def a(): return B.func() 

Aa() returns b_mock.func() which can also be b_mock.func() .

 b_mock.func.return_value = 'spam' Aa() # returns 'spam' 

Note for Python 3: As stated in the change log for 3.0 , __builtin__ now called builtins :

Renamed __builtin__ module to builtins (remove underscores, add and).

The code in this answer works fine if you replace __builtin__ with builtins for Python 3.

+22
Aug 28 '13 at 6:43
source share

How to mock import (mock AB)?

Module A includes import B at the top.

Just, just mock the library in sys.modules before it is imported:

 if wrong_platform(): sys.modules['B'] = mock.MagicMock() 

and then, while A does not rely on the specific data types returned from objects B:

 import A 

must work.

You can also make fun of import AB :

This works even if you have submodules, but you want to mock every module. Say you have this:

 from foo import This, That, andTheOtherThing from foo.bar import Yada, YadaYada from foo.baz import Blah, getBlah, boink 

To laugh, simply follow below before importing the module that contains the above:

 sys.modules['foo'] = MagicMock() sys.modules['foo.bar'] = MagicMock() sys.modules['foo.baz'] = MagicMock() 

(My experience: I had a dependency that worked on the same platform, Windows, but didnโ€™t work on Linux, where we run daily tests. So I needed to make fun of the dependency for our tests. Fortunately, it was a black box, so I donโ€™t it was necessary to establish a lot of interaction.)

Wet side effects

Application: Actually, I needed to simulate a side effect, which took some time. So I needed an object method to sleep for a second. This will work as follows:

 sys.modules['foo'] = MagicMock() sys.modules['foo.bar'] = MagicMock() sys.modules['foo.baz'] = MagicMock() # setup the side-effect: from time import sleep def sleep_one(*args): sleep(1) # this gives us the mock objects that will be used from 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, like the real method.

+13
May 9 '16 at 10:17
source share

I understand that I'm a little late to the party here, but here is a slightly crazy way to automate this using the mock library:

(here is an example of use)

 import contextlib import collections import mock import sys def fake_module(**args): return (collections.namedtuple('module', args.keys())(**args)) def get_patch_dict(dotted_module_path, module): patch_dict = {} module_splits = dotted_module_path.split('.') # Add our module to the patch dict patch_dict[dotted_module_path] = module # We add the rest of the fake modules in backwards while module_splits: # This adds the next level up into the patch dict which is a fake # module that points at the next level down patch_dict['.'.join(module_splits[:-1])] = fake_module( **{module_splits[-1]: patch_dict['.'.join(module_splits)]} ) module_splits = module_splits[:-1] return patch_dict with mock.patch.dict( sys.modules, get_patch_dict('herp.derp', fake_module(foo='bar')) ): import herp.derp # prints bar print herp.derp.foo 

The reason this is so ridiculously complicated is because when the import happens, python basically does it (e.g. from herp.derp import foo )

  • Does sys.modules['herp'] ? Otherwise, import it. If Still Not ImportError
  • Does sys.modules['herp.derp'] ? Otherwise, import it. If Still Not ImportError
  • Get the foo attribute from sys.modules['herp.derp'] . Else ImportError
  • foo = sys.modules['herp.derp'].foo

There are some drawbacks to this hacked solution: if something else relies on other things in the module, this type of screw ends. Also this only works for things that are imported into a string, e.g.

 def foo(): import herp.derp 

or

 def foo(): __import__('herp.derp') 
+7
Aug 19 '13 at 3:34 on
source share

If you execute import ModuleB , you really call the __import__ built-in method as:

 ModuleB = __import__('ModuleB', globals(), locals(), [], -1) 

You can overwrite this method by importing the __builtin__ module and creating a wrapper around the __builtin__.__import__ . Or you can play with the NullImporter hook from the imp module. Catching an exception and debugging your module / class in except -block.

Pointer to relevant documents:

docs.python.org: __import__

Access internal import components using the imp module

Hope this helps. Be HIGHLY advised that you go into the more mysterious perimeters of Python programming and that a) a solid understanding of what you really want to achieve, and b) a deep understanding of the consequences is important.

+3
Dec 28 '11 at 16:15
source share

I found a great way to mock import in Python. This Eric Zaadi solution is found here , which I just use in my Django application.

I have a SeatInterface class, which is the interface of the Seat class. Therefore, inside my seat_interface module, I have this import:

 from ..models import Seat class SeatInterface(object): (...) 

I wanted to create isolated tests for the SeatInterface class with the Seat class as FakeSeat . The problem was how tu runs tests offline when the Django application is down. I had an error:

Incorrect Configured: The BASE_DIR setting was requested, but the settings were not configured. You must either define the DJANGO_SETTINGS_MODULE environment variable or call settings.configure () before accessing Settings.

Ran 1 test at 0.078s

FAILED (errors = 1)

Decision:

 import unittest from mock import MagicMock, patch class FakeSeat(object): pass class TestSeatInterface(unittest.TestCase): def setUp(self): models_mock = MagicMock() models_mock.Seat.return_value = FakeSeat modules = {'app.app.models': models_mock} patch.dict('sys.modules', modules).start() def test1(self): from app.app.models_interface.seat_interface import SeatInterface 

And then the test magically runs normally :)

.
Ran 1 test in 0.002s

Ok

+3
Jul 04 '17 at 20:52
source share

You can use patch and MagicMock

 #Python3.4 from unittest.mock import patch, MagicMock #older versions from mock import patch, MagicMock import A mock = MagicMock() class ATestCase(TestCase): def setUp(): #function mock.foo.return_value = 'value' #variable mock.bar=1234 @patch('B',mock) test_a_should_display_info(self): #code and assert print(AB) #<MagicMock id='140047253898912'> 
0
Oct. 14 '15 at 19:36
source share



All Articles