가져오기를 모의 실행하는 방법
»A를 포함합니다.import B맨 위에하지만 테스트 조건에서 나는 조롱하고 싶습니다. BA)로 표시됩니다.A.B및합니다.B.
실은.B는 일부러 테스트 환경에 설치되지 않습니다.
A테스트 대상 장치입니다.는 가와야합다를 수입해야 .A모든 기능을 갖추고 있습니다. B제가 조롱해야 할 모듈입니다.하지만 어떻게 조롱할 수 있습니까?B에 내에A그리고 멈춤A진짜를 수입하는 것으로부터.B 우선은A Import does is ImportB?
(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. 은, B.py 을 실행하는 에는 ▁does 을 사용할 수 있습니다.test.py되지 않고 "오류"가 반환됩니다.print(A.B.__name__)mock_B 합니다.mock_B.py이 조롱하는 곳 네가조롱는곳하▁you곳.B의 실제 기능/기능/기능 등또는 그냥 할당할 수 있습니다.Mock()직접:
test.py :
import sys
sys.modules['B'] = Mock()
import A
된 제공본기.__import__제어를 할 수 .: 더 많 제 슬 ' 립 브 ' 라 리 사 있 수 조 니 습 다 할 롱 여 하 용 를 러 은 이 어 위 를 해 니 있 다 ▁can ▁for 습 ▁library 더 ▁with ▁be' ▁' :
# 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'
Python 3에 대한 참고: 3.0에 대한 변경 로그에 명시된 바와 같이,__builtin__이제 이름이 지정되었습니다.builtins:
이름이 모듈 이름으로
__builtin__builtins하여 밑줄을
이 답변의 코드는 교체할 경우 정상적으로 작동합니다.__builtin__타고builtinsPython 3:
수입품을 조롱하는 방법, (농담 A.?
모듈 A는 상단에 가져오기 B를 포함합니다.
쉽게, 가져오기 전에 sys.modules의 라이브러리를 조롱하기만 하면 됩니다.
if wrong_platform():
sys.modules['B'] = mock.MagicMock()
, ,속계.AB의 객체에서 반환되는 특정 유형의 데이터에 의존하지 않습니다.
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)
그리고 코드를 실행하는 데는 실제 방법처럼 시간이 걸립니다.
애런 홀의 대답은 저에게 효과가 있습니다.한 가지 중요한 것을 언급하고 싶습니다.
의 경우에는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()
제가 여기 파티에 조금 늦었다는 것을 알지만, 여기 이것을 자동화하는 약간 미친 방법이 있습니다.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 - 성속 기오가져 가져오기
foosys.modules['herp.derp'].또 다른ImportError foo = sys.modules['herp.derp'].foo
함께 해킹된 이 솔루션에는 몇 가지 단점이 있습니다.만약 다른 것이 모듈 경로의 다른 것에 의존한다면, 이것은 그것을 망칩니다.또한 이 기능은 다음과 같이 인라인으로 가져오는 항목에 대해서만 작동합니다.
def foo():
import herp.derp
또는
def foo():
__import__('herp.derp')
파이썬에서 수입품을 조롱할 수 있는 좋은 방법을 찾았습니다.이것은 에릭의 Zaadi 솔루션입니다. 제가 방금 Django 애플리케이션 안에서 사용하고 있습니다.
수업이 있어요.SeatInterface는 대인스다니입이터페의 인터페이스입니다.Seat모범 계급그래서 내 안에seat_interface모듈 나는 다음과 같은 것을 가지고 있습니다.
from ..models import Seat
class SeatInterface(object):
(...)
다음을 위한 격리된 테스트를 만들고 싶었습니다.SeatInterface당한 Seat로 분류하다.FakeSeat문제는 turun이 Django 애플리케이션이 다운된 오프라인에서 테스트하는 방법이었습니다.아래 오류가 있었습니다.
부적절하게 구성됨: BASE_DIR 설정을 요청했지만 설정이 구성되지 않았습니다.설정에 액세스하기 전에 환경 변수 DJANO_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
그리고 나서 마법처럼 테스트가 실행됩니다. OK :)
.
0.002초 내에 1개 테스트 실행네 알겠습니다
만약 당신이import ModuleB당신은 정말로 내장된 방법을 부르고 있습니다.__import__다음과 같이:
ModuleB = __import__('ModuleB', globals(), locals(), [], -1)
다음을 가져와 이 메서드를 덮어쓸 수 있습니다.__builtin__를 만듭니다.__builtin__.__import__방법. 할 수도 . 아니면 당신은 그것을 가지고 놀 수 있습니다.NullImporter에▁the에서 imp. 예클포/래스를에서 except -블록.
관련 문서에 대한 포인터:
docs..org : 문서.python.org :__import__
이것이 도움이 되길 바랍니다.파이썬 프로그래밍의 더 난해한 경계에 발을 들여놓고 a) 정말로 달성하고 싶은 것이 무엇인지를 확실하게 이해하고 b) 그 의미에 대한 철저한 이해가 중요하다는 것을 강조합니다.
저는 이것이 꽤 오래된 질문이라는 것을 알지만, 저는 최근 몇 번 그것으로 돌아가는 제 자신을 발견했고, 이것에 대한 간결한 해결책을 공유하고 싶었습니다.
import sys
from unittest import mock
def mock_module_import(module):
"""Source: https://stackoverflow.com/a/63584866/3972558"""
def _outer_wrapper(func):
def _inner_wrapper(*args, **kwargs):
orig = sys.modules.get(module) # get the original module, if present
sys.modules[module] = mock.MagicMock() # patch it
try:
return func(*args, **kwargs)
finally:
if orig is not None: # if the module was installed, restore patch
sys.modules[module] = orig
else: # if the module never existed, remove the key
del sys.modules[module]
return _inner_wrapper
return _outer_wrapper
의 키를 임시로 로패치방작다동니식합로으에 패치하는 합니다.sys.modules그런 다음 장식된 기능이 호출된 후 원래 모듈을 복원합니다.이는 테스트 환경에 패키지가 설치되지 않을 수 있는 시나리오 또는 패치가 적용된 모듈이 실제로 자체 내부 원숭이 패치를 수행할 수 있는 보다 복잡한 시나리오에서 사용할 수 있습니다.
다음은 사용 예입니다.
@mock_module_import("some_module")
def test_foo():
# use something that relies upon "some_module" here
assert True
저는 오늘 비슷한 문제에 직면한 저 자신을 발견했고, 그것을 조금 다르게 해결하기로 결정했습니다.Python의machine 하는 것이 을 Python에 .sys.path파이썬이 원래 모듈보다 선호하도록 합니다.
하위 디렉터리에 교체 모듈을 만듭니다. 예:
mkdir -p test/mocked-lib ${EDITOR} test/mocked-lib/B.pyA이 를 "가오기를", "이디리에삽다니입합토렉져"에 삽입합니다.sys.path저는 파이테스트를 사용하고 있습니다. 그래서 저는.test/conftest.py저는 간단히 했습니다.import os.path import sys sys.path.insert(0, os.path.join(os.path.dirname(__file__), "mocked-lib"))
되면, 이제테스실행면되가위트트스,▁▁the실되▁is행▁suite,mocked-lib는 하디렉리접추가다니됩두로로 접두사가 .sys.path그리고.import A사용하다Bmocked-lib.
다음은 다음을 사용하는 방법입니다.contextmanager테스트를 더 깨끗하게 만드는 방법:
Function being tested
def read_secret_from_databricks(scope: str, key: str) -> str:
from pyspark.dbutils import DBUtils
return DBUtils(spark).secrets.get(scope, key)
test code
from contextlib import contextmanager
from unittest import mock
# Usually in conftest.py
@contextmanager
def mocked_import(module_name, my_mock=None) -> mock.Mock:
orig_import = __import__
if not my_mock:
my_mock = mock.MagicMock(name=f'mock_{module_name}')
def import_mock(name, *args):
return my_mock if name == module_name else orig_import(name, *args)
with mock.patch('builtins.__import__', side_effect=import_mock):
yield my_mock
# ---------------------------------------------------------------------
# some testcase.py
# fails with "ModuleNotFoundError: No module named 'dbutils'"
def test_read_secrets():
read_secret_from_databricks('scope1', 'key1')
# Passes
def test_read_secrets_with_mock():
with mocked_import('pyspark.dbutils') as m:
read_secret_from_databricks('scope1', 'key1')
assert mock.call.secrets.get('scope1', 'key1') in m.mock_calls
언급URL : https://stackoverflow.com/questions/8658043/how-to-mock-an-import
'programing' 카테고리의 다른 글
| 여러 값에 대한 Firestore 검색 배열 포함 (0) | 2023.06.06 |
|---|---|
| 오류: Gdal이 설치되어 있지만 R 종속 패키지를 설치하는 동안 gdal-config를 찾을 수 없습니다. (0) | 2023.06.06 |
| 파이썬에서 고유 ID를 생성하려면 어떻게 해야 합니까? (0) | 2023.06.06 |
| Web.config 변환 옵션이 회색으로 표시됨 (0) | 2023.06.06 |
| require()와 library()의 차이점은 무엇입니까? (0) | 2023.06.06 |