모듈 상단에 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’추가)로 변경했습니다.
바꿀 경우이 답변의 코드는 잘 작동 __builtin__
에 의해 builtins
파이썬 3.
답변
수입을 조롱하는 방법, (모의 AB)?
모듈 A에는 맨 위에 가져 오기 B가 포함되어 있습니다.
쉽게 가져 오기 전에 sys.modules에서 라이브러리를 조롱하십시오.
if wrong_platform():
sys.modules['B'] = mock.MagicMock()
그런 다음 A
B의 객체에서 반환되는 특정 유형의 데이터에 의존하지 않는 한 :
import A
그냥 작동해야합니다.
당신은 또한 조롱 할 수 있습니다 import A.B
:
하위 모듈이 있더라도 작동하지만 각 모듈을 조롱하고 싶을 것입니다. 이것을 가지고 있다고 가정 해보십시오.
from foo import This, That, andTheOtherThing
from foo.bar import Yada, YadaYada
from foo.baz import Blah, getBlah, boink
위의 내용을 포함하는 모듈을 가져 오기 전에 간단히 아래를 수행하십시오.
sys.modules['foo'] = MagicMock()
sys.modules['foo.bar'] = MagicMock()
sys.modules['foo.baz'] = MagicMock()
(내 경험 : Windows 하나의 플랫폼에서는 작동하지만 매일 테스트를 실행하는 Linux에서는 작동하지 않는 종속성이 있었으므로 테스트를 위해 종속성을 조롱해야했습니다. 다행히도 블랙 박스였습니다. 상호 작용을 많이 할 필요가 없었습니다.)
조롱 부작용
부록 : 실제로, 시간이 걸린 부작용을 시뮬레이션해야했습니다. 그래서 잠을 자려면 객체의 방법이 필요했습니다. 다음과 같이 작동합니다.
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)
그런 다음 실제 방법과 마찬가지로 코드를 실행하는 데 시간이 걸립니다.
답변
나는 여기 파티에 조금 늦었다는 것을 알고 있지만, mock
라이브러리로 이것을 자동화하는 다소 미친 방법이 있습니다.
(사용 예는 다음과 같습니다)
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
이것이 엄청나게 복잡한 이유는 가져 오기가 파이썬에서 기본적으로 수행되는 경우입니다 (예 from herp.derp import foo
🙂
- 않는
sys.modules['herp']
존재 하는가? 그렇지 않으면 가져옵니다. 여전히 그렇지 않은 경우ImportError
- 않는
sys.modules['herp.derp']
존재 하는가? 그렇지 않으면 가져옵니다. 여전히 그렇지 않은 경우ImportError
- 의 속성
foo
을 가져 옵니다sys.modules['herp.derp']
. 그밖에ImportError
foo = sys.modules['herp.derp'].foo
이 해킹 된 솔루션에는 몇 가지 단점이 있습니다. 모듈 경로의 다른 요소에 의존하는 것이 있으면 이런 종류의 문제가 해결됩니다. 또한 이것은 인라인으로 가져 오는 물건에 대해서만 작동합니다.
def foo():
import herp.derp
또는
def foo():
__import__('herp.derp')
답변
Aaron Hall의 답변이 저에게 효과적입니다. 한 가지 중요한 것을 언급하고 싶을뿐입니다.
에 만약 A.py
당신이
from B.C.D import E
그런 다음 test.py
경로를 따라 모든 모듈을 조롱해야합니다. 그렇지 않으면ImportError
sys.modules['B'] = mock.MagicMock()
sys.modules['B.C'] = mock.MagicMock()
sys.modules['B.C.D'] = mock.MagicMock()
답변
파이썬에서 수입품을 조롱하는 훌륭한 방법을 찾았습니다. 그건 에릭의 Zaadi의 솔루션을 찾을 여기 난 그냥 내 내부에서 사용하는 장고 응용 프로그램입니다.
나는 클래스있어 SeatInterface
하는 인터페이스입니다 Seat
모델 클래스를. 그래서 내 seat_interface
모듈 안에는 그런 수입품이 있습니다.
from ..models import Seat
class SeatInterface(object):
(...)
SeatInterface
mocked Seat
class as로 클래스에 대한 격리 된 테스트를 만들고 싶었습니다 FakeSeat
. 문제는 장고 응용 프로그램이 다운 된 오프라인 실행 테스트 방법입니다. 나는 아래 오류가 있었다 :
잘못 구성됨 : BASE_DIR 설정을 요청했지만 설정이 구성되지 않았습니다. 설정에 액세스하기 전에 환경 변수 DJANGO_SETTINGS_MODULE을 정의하거나 settings.configure ()를 호출해야합니다.
0.078 초에 란 1 테스트
실패 (오류 = 1)
해결책은 다음과 같습니다.
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
그런 다음 테스트가 마술처럼 실행됩니다. 🙂
.
0.002 초에 1 번 테스트 수행확인
답변
당신이 그렇게하면 import ModuleB
실제로 다음과 같이 내장 메소드 __import__
를 호출합니다 .
ModuleB = __import__('ModuleB', globals(), locals(), [], -1)
__builtin__
모듈 을 가져 와서 __builtin__.__import__
메소드 주위에 랩퍼를 작성 하여이 메소드를 겹쳐 쓸 수 있습니다. 또는 모듈 의 NullImporter
후크로 재생할 수 있습니다 imp
. 예외를 except
포착 하고 -block 에서 모듈 / 클래스를 비 웃으십시오.
관련 문서를 가리키는 포인터 :
이게 도움이 되길 바란다. 더 많은 파이썬 프로그래밍 경계로 들어가서 a) 실제로 달성하고자하는 것을 확실하게 이해하고 b) 의미에 대한 철저한 이해가 중요하다는 것을 강력히 충고 하십시오 .