수입을 조롱하는 방법
모듈 상단에 A
포함되어 있습니다 import B
. 그러나 시험 조건 하에서 내가하고 싶은 조롱 B
에 A
(모의 A.B
) 완전히 가져 삼가 B
.
실제로 B
는 테스트 환경에 의도적으로 설치되지 않습니다.
A
테스트중인 단위입니다. A
모든 기능 을 가져와야 합니다. B
내가 조롱해야 할 모듈입니다. 그러나 어떻게 조롱 수 있습니다 B
내 A
및 정지 A
실제를 가져 오기에서 B
제일 먼저하는 경우, A
수입이다합니까 B
?
(B가 설치되지 않은 이유는 빠른 테스트를 위해 pypy를 사용하고 불행히도 B는 아직 pypy와 호환되지 않기 때문입니다.)
어떻게 이럴 수 있습니까?
sys.modules['B']
가져 오기 전에 할당하여 A
원하는 것을 얻을 수 있습니다.
test.py :
import sys
sys.modules['B'] = __import__('mock_B')
import A
print(A.B.__name__)
A.py :
import B
참고 B.py는 존재하지 않지만 실행 중에는 test.py
오류가 반환되지 않고 print(A.B.__name__)
인쇄 mock_B
됩니다. 여전히 mock_B.py
B의 실제 함수 / 변수 등을 조롱 하는 위치 를 만들어야합니다 . 또는 Mock ()을 직접 지정할 수 있습니다.
test.py :
import sys
sys.modules['B'] = Mock()
import A
__import__
더 많은 제어를 위해 'mock'라이브러리로 내장 을 조롱 할 수 있습니다.
# 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
A
다음과 같이 말하십시오 .
import B
def a():
return B.func()
A.a()
b_mock.func()
또한 조롱 할 수있는 반환합니다 .
b_mock.func.return_value = 'spam'
A.a() # returns 'spam'
파이썬 3 주 : 에 명시된 바와 같이 3.0 변경 로그 , __builtin__
지금 이름 builtins
:
모듈 이름
__builtin__
을builtins
(밑줄 제거, '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, andTheOtherThing
from foo.bar import Yada, YadaYada
from 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 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, just like the real method.
I realize I'm a bit late to the party here, but here's a somewhat insane way to automate this with the mock
library:
(here's an example usage)
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 when an import occurs python basically does this (take for example from herp.derp import foo
)
- Does
sys.modules['herp']
exist? Else import it. If still notImportError
- Does
sys.modules['herp.derp']
exist? Else import it. If still notImportError
- Get attribute
foo
ofsys.modules['herp.derp']
. ElseImportError
foo = sys.modules['herp.derp'].foo
There are some downsides to this hacked together solution: If something else relies on other stuff in the module path this kind of screws it over. Also this only works for stuff that is being imported inline such as
def foo():
import herp.derp
or
def foo():
__import__('herp.derp')
If you do an import ModuleB
you are really calling the builtin method __import__
as:
ModuleB = __import__('ModuleB', globals(), locals(), [], -1)
You could overwrite this method by importing the __builtin__
module and make a wrapper around the __builtin__.__import__
method. Or you could play with the NullImporter
hook from the imp
module. Catching the exception and Mock your module/class in the except
-block.
Pointer to the relevant docs:
Accessing Import internals with the imp Module
I hope this helps. Be HIGHLY adviced that you step into the more arcane perimeters of python programming and that a) solid understanding what you really want to achieve and b)thorough understanding of the implications is important.
I found fine way to mock the imports in Python. It's Eric's Zaadi solution found here which I just use inside my Django application.
I've got class SeatInterface
which is interface to Seat
model class. So inside my seat_interface
module I have such an import:
from ..models import Seat
class SeatInterface(object):
(...)
I wanted to create isolated tests for SeatInterface
class with mocked Seat
class as FakeSeat
. The problem was - how tu run tests offline, where Django application is down. I had below error:
ImproperlyConfigured: Requested setting BASE_DIR, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.
Ran 1 test in 0.078s
FAILED (errors=1)
The solution was:
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 test magically runs OK :)
.
Ran 1 test in 0.002sOK
Aaron Hall's answer works for me. Just want to mention one important thing,
if in A.py
you do
from B.C.D import E
then in test.py
you must mock every module along the path, otherwise you get ImportError
sys.moduels['B'] = mock.MagicMock()
sys.moduels['B.C'] = mock.MagicMock()
sys.moduels['B.C.D'] = mock.MagicMock()
참고URL : https://stackoverflow.com/questions/8658043/how-to-mock-an-import
'Programing' 카테고리의 다른 글
파이썬을 기계 코드로 컴파일하는 것이 가능합니까? (0) | 2020.07.13 |
---|---|
Typescript 매개 변수 이름에서 물음표는 무엇입니까 (0) | 2020.07.13 |
유닉스에서 "텍스트 파일 사용중"메시지를 생성하는 것은 무엇입니까? (0) | 2020.07.13 |
Markdown을 사용하여 단락에 클래스 이름을 정의 할 수 있습니까? (0) | 2020.07.13 |
MVC에 다시 쓴 후 GUI가 작동하지 않음 (0) | 2020.07.13 |