unittest.mock
— 모의 객체 라이브러리¶
버전 3.3에 추가.
소스 코드: Lib/unittest/mock.py
unittest.mock
은 파이썬에서 테스트하기 위한 라이브러리입니다. 테스트 대상 시스템의 일부를 모의 객체로 교체하고 그들이 사용된 방식에 대해 어서션(assertion)을 할 수 있습니다.
unittest.mock
은 핵심 Mock
클래스를 제공하여 테스트 스위트 전체에 걸쳐 많은 스텁을 만들 필요가 없도록 합니다. 작업을 수행한 후, 사용된 메서드 / 어트리뷰트와 호출에 제공된 인자에 대한 어서션을 할 수 있습니다. 일반적인 방법으로 반환 값을 지정하고 필요한 어트리뷰트를 설정할 수도 있습니다.
또한, mock은 테스트 스코프 내에서 모듈과 클래스 수준 어트리뷰트의 패치를 처리하는 patch()
데코레이터를 고유한 객체 생성을 위한 sentinel
과 함께 제공합니다. Mock
, MagicMock
및 patch()
사용 방법에 대한 몇 가지 예는 간략 지침을 참조하십시오.
Mock은 unittest
와 함께 사용하도록 설계되었고 많은 모킹(mocking) 프레임워크에서 사용하는 ‘기록(record) -> 재생(replay)’ 대신 ‘액션(action) -> 어서션(assertion)’ 패턴을 기반으로 합니다.
이전 버전의 파이썬을 위한 unittest.mock
의 역 이식이 있습니다, PyPI의 mock에서 제공됩니다.
간략 지침¶
Mock
과 MagicMock
객체는 그것들을 액세스함에 따라 모든 어트리뷰트와 메서드를 작성하고 사용 방식에 대한 세부 사항을 저장합니다. 반환 값을 지정하거나 사용 가능한 어트리뷰트를 제한하도록 구성한 다음, 사용된 방식에 대한 어서션을 만들 수 있습니다:
>>> from unittest.mock import MagicMock
>>> thing = ProductionClass()
>>> thing.method = MagicMock(return_value=3)
>>> thing.method(3, 4, 5, key='value')
3
>>> thing.method.assert_called_with(3, 4, 5, key='value')
side_effect
를 사용하면 모의 객체(mock)가 호출될 때 예외를 발생시키는 것을 포함하여 부작용(side effect)을 수행 할 수 있습니다:
>>> mock = Mock(side_effect=KeyError('foo'))
>>> mock()
Traceback (most recent call last):
...
KeyError: 'foo'
>>> values = {'a': 1, 'b': 2, 'c': 3}
>>> def side_effect(arg):
... return values[arg]
...
>>> mock.side_effect = side_effect
>>> mock('a'), mock('b'), mock('c')
(1, 2, 3)
>>> mock.side_effect = [5, 4, 3, 2, 1]
>>> mock(), mock(), mock()
(5, 4, 3)
Mock은 여러 가지 방법으로 구성하고 동작을 제어 할 수 있습니다. 예를 들어 spec 인자는 다른 객체에서 사양을 가져오도록 모의 객체를 구성합니다. spec에 존재하지 않는 모의 객체의 어트리뷰트나 메서드에 액세스하려고 시도하면 AttributeError
로 실패합니다.
patch()
데코레이터 / 컨텍스트 관리자는 테스트 대상 모듈에서 클래스나 객체를 쉽게 모킹할 수 있도록 합니다. 지정한 객체는 테스트 중에 모의 객체(또는 다른 객체)로 치환되고 테스트가 끝나면 복원됩니다:
>>> from unittest.mock import patch
>>> @patch('module.ClassName2')
... @patch('module.ClassName1')
... def test(MockClass1, MockClass2):
... module.ClassName1()
... module.ClassName2()
... assert MockClass1 is module.ClassName1
... assert MockClass2 is module.ClassName2
... assert MockClass1.called
... assert MockClass2.called
...
>>> test()
참고
patch 데코레이터를 중첩할 때 모의 객체는 적용한 순서와 같은 순서로 데코레이트 되는 함수로 전달됩니다 (데코레이터가 적용되는 일반적인 파이썬 순서). 이것은 아래에서 위로 감을 뜻하므로, 위의 예에서 module.ClassName1
에 대한 모의 객체가 먼저 전달됩니다.
patch()
를 사용할 때 조회되는 이름 공간에서 객체를 패치하는 것이 중요합니다. 이것은 일반적으로 간단하지만, 간략 지침은 패치할 곳을 읽으십시오.
데코레이터 patch()
는 with 문에서 컨텍스트 관리자로 사용할 수도 있습니다:
>>> with patch.object(ProductionClass, 'method', return_value=None) as mock_method:
... thing = ProductionClass()
... thing.method(1, 2, 3)
...
>>> mock_method.assert_called_once_with(1, 2, 3)
스코프 도중 딕셔너리에 값을 설정하고 테스트가 종료될 때 딕셔너리를 원래 상태로 복원하기 위한 patch.dict()
도 있습니다:
>>> foo = {'key': 'value'}
>>> original = foo.copy()
>>> with patch.dict(foo, {'newkey': 'newvalue'}, clear=True):
... assert foo == {'newkey': 'newvalue'}
...
>>> assert foo == original
Mock은 파이썬 매직 메서드의 모킹을 지원합니다. 매직 메서드를 사용하는 가장 쉬운 방법은 MagicMock
클래스를 사용하는 것입니다. 다음과 같은 것을 할 수 있도록 합니다:
>>> mock = MagicMock()
>>> mock.__str__.return_value = 'foobarbaz'
>>> str(mock)
'foobarbaz'
>>> mock.__str__.assert_called_with()
Mock을 사용하면 함수(또는 다른 Mock 인스턴스)를 매직 메서드에 대입할 수 있고 적절하게 호출될 것입니다. MagicMock
클래스는 모든 매직 메서드(아마도, 모든 유용한 메서드)가 미리 만들어져 있는 Mock 변형일 뿐입니다.
다음은 평범한 Mock 클래스로 매직 메서드를 사용하는 예입니다:
>>> mock = Mock()
>>> mock.__str__ = Mock(return_value='wheeeeee')
>>> str(mock)
'wheeeeee'
테스트의 모의 객체가 대체하는 객체와 같은 api를 갖도록, 자동 사양를 사용할 수 있습니다. 자동 사양은 패치 할 autospec 인자를 patch에 전달하거나 create_autospec()
함수를 통해 수행할 수 있습니다. 자동 사양은 대체하는 객체와 같은 어트리뷰트와 메서드를 갖는 모의 객체를 만들고, 모든 함수와 (생성자를 포함한) 메서드는 실제 객체와 같은 호출 서명을 갖습니다.
이것은 모의 객체가 잘못 사용될 경우 프로덕션 코드와 같은 방식으로 실패하도록 합니다:
>>> from unittest.mock import create_autospec
>>> def function(a, b, c):
... pass
...
>>> mock_function = create_autospec(function, return_value='fishy')
>>> mock_function(1, 2, 3)
'fishy'
>>> mock_function.assert_called_once_with(1, 2, 3)
>>> mock_function('wrong arguments')
Traceback (most recent call last):
...
TypeError: <lambda>() takes exactly 3 arguments (1 given)
create_autospec()
이 클래스에 사용되면 __init__
메서드의 서명을 복사하고, 콜러블 객체에 사용되면 __call__
메서드의 서명을 복사합니다.
Mock 클래스¶
Mock
은 코드 전체에서 스텁과 테스트 이중화의 사용을 대체하기 위한 유연한 모의 객체입니다. 모의 객체는 콜러블이고 어트리뷰트에 액세스할 때 새 모의 객체로 어트리뷰트를 만듭니다 [1]. 같은 어트리뷰트에 액세스하면 항상 같은 모의 객체를 반환합니다. 모의 객체는 사용 방법을 기록하여, 코드가 모의 객체에 대해 수행한 작업에 대한 어서션을 만들 수 있도록 합니다.
MagicMock
은 Mock
의 서브 클래스이며, 모든 매직 메서드가 미리 만들어져 사용할 준비가 되어있습니다. 콜러블이 아닌 변형도 있어서, 콜러블이 아닌 객체를 모킹할 때 유용합니다: NonCallableMock
과 NonCallableMagicMock
patch()
데코레이터를 사용하면 특정 모듈의 클래스를 Mock
객체로 쉽게 대체 할 수 있습니다. 기본적으로 patch()
는 MagicMock
을 생성합니다. patch()
에 new_callable 인자를 사용하여 대체 Mock
클래스를 지정할 수 있습니다.
- class unittest.mock.Mock(spec=None, side_effect=None, return_value=DEFAULT, wraps=None, name=None, spec_set=None, unsafe=False, **kwargs)¶
새로운
Mock
객체를 만듭니다.Mock
은 Mock 객체의 동작을 지정하는 몇 가지 선택적 인자를 취합니다:spec: 문자열 리스트이거나 모의 객체의 사양으로 작동하는 기존 객체 (클래스나 인스턴스)일 수 있습니다. 객체를 전달하면 객체에 dir을 호출하여 문자열 리스트가 형성됩니다 (지원되지 않는 매직 어트리뷰트와 메서드는 제외합니다). 이 리스트에 없는 어트리뷰트에 액세스하면
AttributeError
가 발생합니다.spec이 (문자열 리스트 대신에) 객체이면,
__class__
는 spec 객체의 클래스를 반환합니다. 이것은 모의 객체가isinstance()
검사를 통과할 수 있도록 합니다.spec_set: spec의 더 엄격한 변형. 사용되면, spec_set으로 전달된 객체에 없는 모의 객체의 어트리뷰트를 설정하거나 얻으려고 시도하면
AttributeError
가 발생합니다.side_effect: Mock이 호출될 때마다 호출되는 함수.
side_effect
어트리뷰트를 참조하십시오. 예외를 발생시키거나 반환 값을 동적으로 변경하는 데 유용합니다. 함수는 모의 객체와 같은 인자로 호출되며,DEFAULT
를 반환하지 않는 한, 이 함수의 반환 값이 반환 값으로 사용됩니다.또는 side_effect는 예외 클래스나 인스턴스일 수 있습니다. 이 경우 모의 객체가 호출될 때 그 예외가 발생합니다.
side_effect가 이터러블이면 모의 객체에 대한 각 호출은 이터러블의 다음 값을 반환합니다.
side_effect는
None
으로 설정하여 지울 수 있습니다.return_value: 모의 객체가 호출될 때 반환되는 값. 기본적으로 이것은 새로운 Mock입니다 (처음 액세스할 때 만들어집니다).
return_value
어트리뷰트를 참조하십시오.unsafe: By default, accessing any attribute whose name starts with assert, assret, asert, aseert or assrt will raise an
AttributeError
. Passingunsafe=True
will allow access to these attributes.버전 3.5에 추가.
wraps: 모의 객체가 감쌀 항목. wraps가
None
이 아니면 Mock을 호출할 때 래핑 된 객체로 호출이 전달됩니다 (실제 결과를 반환합니다). 모의 객체에 대한 어트리뷰트 액세스는 래핑 된 객체의 해당 어트리뷰트를 래핑하는 Mock 객체를 반환합니다 (따라서 존재하지 않는 어트리뷰트에 액세스하려고 시도하면AttributeError
가 발생합니다).모의 객체에 명시적으로 return_value가 설정되면 호출은 래핑 된 객체로 전달되지 않고 대신 return_value가 반환됩니다.
name: 모의 객체에 이름이 있으면 모의 객체의 repr에 사용됩니다. 디버깅에 유용할 수 있습니다. 이름은 자식 모의 객체로 전파됩니다.
임의의 키워드 인자로 모의 객체를 호출할 수도 있습니다. 이것들은 모의 객체가 만들어진 후에 어트리뷰트를 설정하는 데 사용됩니다. 자세한 내용은
configure_mock()
메서드를 참조하십시오.- assert_called()¶
모의 객체가 적어도 한 번 호출되었다고 어서트 합니다.
>>> mock = Mock() >>> mock.method() <Mock name='mock.method()' id='...'> >>> mock.method.assert_called()
버전 3.6에 추가.
- assert_called_once()¶
모의 객체가 정확히 한 번 호출되었다고 어서트 합니다.
>>> mock = Mock() >>> mock.method() <Mock name='mock.method()' id='...'> >>> mock.method.assert_called_once() >>> mock.method() <Mock name='mock.method()' id='...'> >>> mock.method.assert_called_once() Traceback (most recent call last): ... AssertionError: Expected 'method' to have been called once. Called 2 times.
버전 3.6에 추가.
- assert_called_with(*args, **kwargs)¶
이 메서드는 마지막 호출이 특정 방식으로 이루어졌음을 어서트하는 편리한 방법입니다:
>>> mock = Mock() >>> mock.method(1, 2, 3, test='wow') <Mock name='mock.method()' id='...'> >>> mock.method.assert_called_with(1, 2, 3, test='wow')
- assert_called_once_with(*args, **kwargs)¶
Assert that the mock was called exactly once and that call was with the specified arguments.
>>> mock = Mock(return_value=None) >>> mock('foo', bar='baz') >>> mock.assert_called_once_with('foo', bar='baz') >>> mock('other', bar='values') >>> mock.assert_called_once_with('other', bar='values') Traceback (most recent call last): ... AssertionError: Expected 'mock' to be called once. Called 2 times.
- assert_any_call(*args, **kwargs)¶
지정된 인자로 모의 객체가 호출되었다고 어서트 합니다.
호출이 가장 최근 호출일 때만 통과하는
assert_called_with()
와assert_called_once_with()
, 그리고assert_called_once_with()
의 경우 유일한 호출이어야 하는 것과 달리 모의 객체가 호출된 적이 있으면 어서트가 통과합니다.>>> mock = Mock(return_value=None) >>> mock(1, 2, arg='thing') >>> mock('some', 'thing', 'else') >>> mock.assert_any_call(1, 2, arg='thing')
- assert_has_calls(calls, any_order=False)¶
지정된 호출로 모의 객체가 호출되었다고 어서트 합니다. calls에 대해
mock_calls
리스트를 검사합니다.any_order가 거짓이면 호출은 순차적이어야 합니다. 지정된 호출 전후에 추가 호출이 있을 수 있습니다.
any_order가 참이면 호출 순서는 상관없지만, 모두
mock_calls
에 나타나야 합니다.>>> mock = Mock(return_value=None) >>> mock(1) >>> mock(2) >>> mock(3) >>> mock(4) >>> calls = [call(2), call(3)] >>> mock.assert_has_calls(calls) >>> calls = [call(4), call(2), call(3)] >>> mock.assert_has_calls(calls, any_order=True)
- assert_not_called()¶
모의 객체가 호출되지 않았다고 어서트 합니다.
>>> m = Mock() >>> m.hello.assert_not_called() >>> obj = m.hello() >>> m.hello.assert_not_called() Traceback (most recent call last): ... AssertionError: Expected 'hello' to not have been called. Called 1 times.
버전 3.5에 추가.
- reset_mock(*, return_value=False, side_effect=False)¶
reset_mock 메서드는 모의 객체의 모든 호출 어트리뷰트를 재설정합니다:
>>> mock = Mock(return_value=None) >>> mock('hello') >>> mock.called True >>> mock.reset_mock() >>> mock.called False
버전 3.6에서 변경: Added two keyword-only arguments to the reset_mock function.
같은 객체를 재사용하는 일련의 어서션을 만들려는 경우에 유용할 수 있습니다.
reset_mock()
은 기본적으로 정규 대입을 사용하여 설정한 반환 값,side_effect
또는 모든 자식 어트리뷰트를 지우지 않음에 유의하십시오. return_value나side_effect
를 재설정하려면, 해당 매개 변수를True
로 전달하십시오. 자식 모의 객체와 반환 값 모의 객체(있다면)도 재설정됩니다.참고
return_value, and
side_effect
are keyword-only arguments.
- mock_add_spec(spec, spec_set=False)¶
모의 객체에 사양을 추가합니다. spec은 객체이거나 문자열 리스트일 수 있습니다. spec의 어트리뷰트 만 모의 객체에서 어트리뷰트로 꺼낼 수 있습니다.
spec_set이 참이면 스펙에 있는 어트리뷰트 만 설정할 수 있습니다.
- attach_mock(mock, attribute)¶
이름과 부모를 치환해서, 이것의 어트리뷰트(attribute)로 모의 객체(mock)를 연결합니다. 연결된 모의 객체에 대한 호출은 이것의
method_calls
와mock_calls
어트리뷰트에 기록됩니다.
- configure_mock(**kwargs)¶
키워드 인자를 통해 모의 객체의 어트리뷰트를 설정합니다.
표준 점 표기법과 메서드 호출에서 딕셔너리 언 패킹을 사용해서 자식 모의 객체에 어트리뷰트와 반환 값 및 부작용을 설정할 수 있습니다:
>>> mock = Mock() >>> attrs = {'method.return_value': 3, 'other.side_effect': KeyError} >>> mock.configure_mock(**attrs) >>> mock.method() 3 >>> mock.other() Traceback (most recent call last): ... KeyError
모의 객체에 대한 생성자 호출에서 같은 것을 할 수 있습니다:
>>> attrs = {'method.return_value': 3, 'other.side_effect': KeyError} >>> mock = Mock(some_attribute='eggs', **attrs) >>> mock.some_attribute 'eggs' >>> mock.method() 3 >>> mock.other() Traceback (most recent call last): ... KeyError
configure_mock()
은 모의 객체를 만든 후에 구성을 더 쉽게 할 수 있도록 하기 위해 존재합니다.
- __dir__()¶
Mock
객체는dir(some_mock)
의 결과를 유용한 결과로 제한합니다. spec이 있는 모의 객체에서 이것은 모의 객체에 허용되는 모든 어트리뷰트를 포함합니다.이 필터링이 하는 일과 해제 방법에 대해서는
FILTER_DIR
을 참조하십시오.
- _get_child_mock(**kw)¶
어트리뷰트와 반환 값에 대한 자식 모의 객체를 만듭니다. 기본적으로 자식 모의 객체는 부모와 같은 형입니다. Mock의 서브 클래스는 자식 모의 객체가 만들어지는 방법을 사용자 정의하기 위해 이를 재정의할 수 있습니다.
콜러블이 아닌 모의 객체의 경우 (사용자 정의 서브 클래스 대신) 콜러블 변형이 사용됩니다.
- called¶
모의 객체가 호출되었는지를 나타내는 불리언:
>>> mock = Mock(return_value=None) >>> mock.called False >>> mock() >>> mock.called True
- call_count¶
모의 객체가 몇 번이나 호출되었는지를 알려주는 정수:
>>> mock = Mock(return_value=None) >>> mock.call_count 0 >>> mock() >>> mock() >>> mock.call_count 2
- return_value¶
모의 객체를 호출할 때 반환되는 값을 구성하려면 이것을 설정하십시오:
>>> mock = Mock() >>> mock.return_value = 'fish' >>> mock() 'fish'
기본 반환 값은 모의 객체이며 일반적인 방식으로 구성할 수 있습니다:
>>> mock = Mock() >>> mock.return_value.attribute = sentinel.Attribute >>> mock.return_value() <Mock name='mock()()' id='...'> >>> mock.return_value.assert_called_with()
생성자에서
return_value
를 설정할 수도 있습니다:>>> mock = Mock(return_value=3) >>> mock.return_value 3 >>> mock() 3
- side_effect¶
이것은 모의 객체가 호출될 때 호출되는 함수, 이터러블 또는 발생시킬 예외(클래스나 인스턴스)일 수 있습니다.
함수를 전달하면 모의 객체와 같은 인자로 호출되며 함수가
DEFAULT
싱글톤을 반환하지 않는 한 모의 객체에 대한 호출은 함수가 반환하는 것을 반환합니다. 함수가DEFAULT
를 반환하면 모의 객체는 (return_value
에서) 정상값을 반환합니다.이터러블을 전달하면, 모든 호출에서 값을 산출해야 하는 이터레이터를 얻는 데 사용됩니다. 이 값은 발생시킬 예외 인스턴스나 모의 객체 호출에서 반환될 값일 수 있습니다 (
DEFAULT
처리는 함수 경우와 같습니다).(API의 예외 처리를 테스트하기 위해) 예외를 발생시키는 모의 객체 예:
>>> mock = Mock() >>> mock.side_effect = Exception('Boom!') >>> mock() Traceback (most recent call last): ... Exception: Boom!
side_effect
를 사용하여 일련의 값을 반환하기:>>> mock = Mock() >>> mock.side_effect = [3, 2, 1] >>> mock(), mock(), mock() (3, 2, 1)
콜러블 사용하기:
>>> mock = Mock(return_value=3) >>> def side_effect(*args, **kwargs): ... return DEFAULT ... >>> mock.side_effect = side_effect >>> mock() 3
생성자에서
side_effect
를 설정할 수 있습니다. 다음은 모의 객체가 호출된 값에 1을 더해서 반환하는 예입니다:>>> side_effect = lambda value: value + 1 >>> mock = Mock(side_effect=side_effect) >>> mock(3) 4 >>> mock(-8) -7
side_effect
를None
으로 설정하면 지워집니다:>>> m = Mock(side_effect=KeyError, return_value=3) >>> m() Traceback (most recent call last): ... KeyError >>> m.side_effect = None >>> m() 3
- call_args¶
이것은
None
(모의 객체가 호출되지 않았을 때)이거나 모의 객체가 마지막으로 호출된 인자입니다. 이것은 튜플 형태입니다:args
프로퍼티를 통해 액세스 할 수도 있는 첫 번째 멤버는 모의 객체를 호출한 순서 있는 인자(또는 빈 튜플)이며kwargs
프로퍼티를 통해 액세스 할 수도 있는 두 번째 멤버는 모든 키워드 인자(또는 빈 딕셔너리)입니다.>>> mock = Mock(return_value=None) >>> print(mock.call_args) None >>> mock() >>> mock.call_args call() >>> mock.call_args == () True >>> mock(3, 4) >>> mock.call_args call(3, 4) >>> mock.call_args == ((3, 4),) True >>> mock.call_args.args (3, 4) >>> mock.call_args.kwargs {} >>> mock(3, 4, 5, key='fish', next='w00t!') >>> mock.call_args call(3, 4, 5, key='fish', next='w00t!') >>> mock.call_args.args (3, 4, 5) >>> mock.call_args.kwargs {'key': 'fish', 'next': 'w00t!'}
call_args_list
,method_calls
및mock_calls
리스트의 멤버와 함께call_args
는call
객체입니다. 이들은 튜플이므로, 개별 인자를 얻고 더 복잡한 어서션을 하기 위해 언팩할 수 있습니다. call 튜플을 참조하십시오.버전 3.8에서 변경:
args
와kwargs
프로퍼티를 추가했습니다.
- call_args_list¶
이것은 모의 객체에 대한 모든 호출을 순서대로 나열한 리스트입니다 (따라서 리스트의 길이는 호출된 횟수입니다). 호출이 있기 전에는 빈 리스트입니다.
call
객체는call_args_list
와 비교할 호출 리스트를 편리하게 구성하는 데 사용할 수 있습니다.>>> mock = Mock(return_value=None) >>> mock() >>> mock(3, 4) >>> mock(key='fish', next='w00t!') >>> mock.call_args_list [call(), call(3, 4), call(key='fish', next='w00t!')] >>> expected = [(), ((3, 4),), ({'key': 'fish', 'next': 'w00t!'},)] >>> mock.call_args_list == expected True
call_args_list
의 멤버는call
객체입니다. 이들은 개별 인자를 얻기 위해 튜플로서 언팩될 수 있습니다. call 튜플을 참조하십시오.
- method_calls¶
자신에 대한 호출 추적뿐만 아니라, 모의 객체는 메서드와 어트리뷰트, 그리고 그들의 메서드와 어트리뷰트에 대한 호출도 추적합니다:
>>> mock = Mock() >>> mock.method() <Mock name='mock.method()' id='...'> >>> mock.property.method.attribute() <Mock name='mock.property.method.attribute()' id='...'> >>> mock.method_calls [call.method(), call.property.method.attribute()]
method_calls
의 멤버는call
객체입니다. 이들은 개별 인자를 얻기 위해 튜플로서 언팩될 수 있습니다. call 튜플을 참조하십시오.
- mock_calls¶
mock_calls
는 모의 객체, 그것의 메서드, 매직 메서드 및 반환 값 모의 객체에 대한 모든 호출을 기록합니다.>>> mock = MagicMock() >>> result = mock(1, 2, 3) >>> mock.first(a=3) <MagicMock name='mock.first()' id='...'> >>> mock.second() <MagicMock name='mock.second()' id='...'> >>> int(mock) 1 >>> result(1) <MagicMock name='mock()()' id='...'> >>> expected = [call(1, 2, 3), call.first(a=3), call.second(), ... call.__int__(), call()(1)] >>> mock.mock_calls == expected True
mock_calls
의 멤버는call
객체입니다. 이들은 개별 인자를 얻기 위해 튜플로서 언팩될 수 있습니다. call 튜플을 참조하십시오.참고
mock_calls
가 기록되는 방식은 중첩된 호출이 수행될 때 상위 호출의 매개 변수가 기록되지 않아서 항상 같다고 비교됨을 뜻합니다.:>>> mock = MagicMock() >>> mock.top(a=3).bottom() <MagicMock name='mock.top().bottom()' id='...'> >>> mock.mock_calls [call.top(a=3), call.top().bottom()] >>> mock.mock_calls[-1] == call.top(a=-1).bottom() True
- __class__¶
일반적으로 객체의
__class__
어트리뷰트는 해당 형을 반환합니다.spec
이 있는 모의 객체의 경우,__class__
는 대신 spec 클래스를 반환합니다. 이를 통해 모의 객체는 다음과 같이 대체 / 가장하는 객체에 대한isinstance()
테스트를 통과할 수 있습니다:>>> mock = Mock(spec=3) >>> isinstance(mock, int) True
__class__
는 대입할 수 있습니다. 이를 통해 spec을 사용하지 않고도 모의 객체가isinstance()
검사를 통과할 수 있습니다.:>>> mock = Mock() >>> mock.__class__ = dict >>> isinstance(mock, dict) True
- class unittest.mock.NonCallableMock(spec=None, wraps=None, name=None, spec_set=None, **kwargs)¶
콜러블이 아닌
Mock
버전. 생성자 매개 변수는Mock
과 같은 의미를 가지며, 콜러블이 아닌 모의 객체에서 의미가 없는 return_value와 side_effect는 예외입니다.
클래스 나 인스턴스를 spec
이나 spec_set
으로 사용하는 모의 객체는 isinstance()
테스트를 통과할 수 있습니다:
>>> mock = Mock(spec=SomeClass)
>>> isinstance(mock, SomeClass)
True
>>> mock = Mock(spec_set=SomeClass())
>>> isinstance(mock, SomeClass)
True
Mock
클래스는 매직 메서드 모킹을 지원합니다. 자세한 내용은 매직 메서드를 참조하십시오.
모의 객체 클래스와 patch()
데코레이터는 모두 구성을 위해 임의의 키워드 인자를 취합니다. patch()
데코레이터의 경우 키워드는 만들어지는 모의 객체의 생성자로 전달됩니다. 키워드 인자는 모의 객체의 어트리뷰트를 구성하기 위한 것입니다.:
>>> m = MagicMock(attribute=3, other='fish')
>>> m.attribute
3
>>> m.other
'fish'
자식 모의 객체의 반환 값과 부작용은 점 표기법을 사용하여 같은 방식으로 설정할 수 있습니다. 호출에서 점으로 구분된 이름을 직접 사용할 수 없어서 딕셔너리를 만들고 **
를 사용하여 언팩해야 합니다:
>>> attrs = {'method.return_value': 3, 'other.side_effect': KeyError}
>>> mock = Mock(some_attribute='eggs', **attrs)
>>> mock.some_attribute
'eggs'
>>> mock.method()
3
>>> mock.other()
Traceback (most recent call last):
...
KeyError
spec(또는 spec_set)으로 만들어진 콜러블 모의 객체는 호출을 모의 객체와 일치시킬 때 사양 객체의 서명을 검사합니다. 따라서, 위치나 이름으로 전달되었는지와 관계없이 실제 호출의 인자와 일치할 수 있습니다:
>>> def f(a, b, c): pass
...
>>> mock = Mock(spec=f)
>>> mock(1, 2, c=3)
<Mock name='mock()' id='140161580456576'>
>>> mock.assert_called_with(1, 2, 3)
>>> mock.assert_called_with(a=1, b=2, c=3)
이것은 assert_called_with()
, assert_called_once_with()
, assert_has_calls()
및 assert_any_call()
에 적용됩니다. 자동 사양할 때, 모의 객체의 메서드 호출에도 적용됩니다.
버전 3.4에서 변경: spec 되거나 자동 사양된 모의 객체에 대한 서명 검사를 추가했습니다.
- class unittest.mock.PropertyMock(*args, **kwargs)¶
A mock intended to be used as a
property
, or other descriptor, on a class.PropertyMock
provides__get__()
and__set__()
methods so you can specify a return value when it is fetched.객체에서
PropertyMock
인스턴스를 가져오면 인자 없이 모의 객체를 호출합니다. 설정하면 설정되는 값으로 모의 객체를 호출합니다.>>> class Foo: ... @property ... def foo(self): ... return 'something' ... @foo.setter ... def foo(self, value): ... pass ... >>> with patch('__main__.Foo.foo', new_callable=PropertyMock) as mock_foo: ... mock_foo.return_value = 'mockity-mock' ... this_foo = Foo() ... print(this_foo.foo) ... this_foo.foo = 6 ... mockity-mock >>> mock_foo.mock_calls [call(), call(6)]
모의 객체 어트리뷰트가 저장되는 방식으로 인해 PropertyMock
을 모의 객체에 직접 연결할 수 없습니다. 대신 모의 객체의 형 객체에 연결할 수 있습니다:
>>> m = MagicMock()
>>> p = PropertyMock(return_value=3)
>>> type(m).foo = p
>>> m.foo
3
>>> p.assert_called_once_with()
- class unittest.mock.AsyncMock(spec=None, side_effect=None, return_value=DEFAULT, wraps=None, name=None, spec_set=None, unsafe=False, **kwargs)¶
MagicMock
의 비동기 버전.AsyncMock
객체는 객체가 비동기 함수로 인식되도록 동작하고, 호출 결과는 어웨이터블 입니다.>>> mock = AsyncMock() >>> asyncio.iscoroutinefunction(mock) True >>> inspect.isawaitable(mock()) True
mock()
의 결과는 어웨이트 한 후side_effect
나return_value
를 제공하는 비동기 함수입니다:side_effect
가 함수이면, 비동기 함수는 해당 함수의 결과를 반환합니다,side_effect
가 예외이면, 비동기 함수는 예외를 발생시킵니다,side_effect
가 이터러블이면, 비동기 함수는 이터러블의 다음 값을 반환하지만, 결과 시퀀스가 소진되면StopAsyncIteration
이 즉시 발생합니다,side_effect
가 정의되지 않으면, 비동기 함수는return_value
에 의해 정의된 값을 반환하므로, 기본적으로 비동기 함수는 새AsyncMock
객체를 반환합니다.
Mock
이나MagicMock
의 spec을 비동기 함수로 설정하면 호출 후에 코루틴 객체가 반환됩니다.>>> async def async_func(): pass ... >>> mock = MagicMock(async_func) >>> mock <MagicMock spec='function' id='...'> >>> mock() <coroutine object AsyncMockMixin._mock_call at ...>
Mock
,MagicMock
또는AsyncMock
의 spec을 비동기와 동기 함수가 있는 클래스로 설정하면 동기 함수를 자동으로 감지하고 그들을MagicMock
(부모 모의 객체가AsyncMock
이나MagicMock
일 때)이나Mock
(부모 모의 객체가Mock
일 때)으로 설정합니다. 모든 비동기 함수는AsyncMock
이 됩니다.>>> class ExampleClass: ... def sync_foo(): ... pass ... async def async_foo(): ... pass ... >>> a_mock = AsyncMock(ExampleClass) >>> a_mock.sync_foo <MagicMock name='mock.sync_foo' id='...'> >>> a_mock.async_foo <AsyncMock name='mock.async_foo' id='...'> >>> mock = Mock(ExampleClass) >>> mock.sync_foo <Mock name='mock.sync_foo' id='...'> >>> mock.async_foo <AsyncMock name='mock.async_foo' id='...'>
버전 3.8에 추가.
- assert_awaited()¶
모의 객체가 적어도 한 번 어웨이트 되었다고 어서트 합니다. 이것은 호출된 객체와 별개임에 유의하십시오,
await
키워드를 반드시 사용해야 합니다:>>> mock = AsyncMock() >>> async def main(coroutine_mock): ... await coroutine_mock ... >>> coroutine_mock = mock() >>> mock.called True >>> mock.assert_awaited() Traceback (most recent call last): ... AssertionError: Expected mock to have been awaited. >>> asyncio.run(main(coroutine_mock)) >>> mock.assert_awaited()
- assert_awaited_once()¶
모의 객체가 정확히 한 번 어웨이트 되었다고 어서트 합니다.
>>> mock = AsyncMock() >>> async def main(): ... await mock() ... >>> asyncio.run(main()) >>> mock.assert_awaited_once() >>> asyncio.run(main()) >>> mock.method.assert_awaited_once() Traceback (most recent call last): ... AssertionError: Expected mock to have been awaited once. Awaited 2 times.
- assert_awaited_with(*args, **kwargs)¶
마지막 어웨이트가 지정된 인자로 이루어졌다고 어서트 합니다.
>>> mock = AsyncMock() >>> async def main(*args, **kwargs): ... await mock(*args, **kwargs) ... >>> asyncio.run(main('foo', bar='bar')) >>> mock.assert_awaited_with('foo', bar='bar') >>> mock.assert_awaited_with('other') Traceback (most recent call last): ... AssertionError: expected call not found. Expected: mock('other') Actual: mock('foo', bar='bar')
- assert_awaited_once_with(*args, **kwargs)¶
모의 객체가 정확히 한 번, 지정된 인자로 어웨이트 되었다고 어서트 합니다.
>>> mock = AsyncMock() >>> async def main(*args, **kwargs): ... await mock(*args, **kwargs) ... >>> asyncio.run(main('foo', bar='bar')) >>> mock.assert_awaited_once_with('foo', bar='bar') >>> asyncio.run(main('foo', bar='bar')) >>> mock.assert_awaited_once_with('foo', bar='bar') Traceback (most recent call last): ... AssertionError: Expected mock to have been awaited once. Awaited 2 times.
- assert_any_await(*args, **kwargs)¶
지정된 인자로 모의 객체가 어웨이트된 적이 있다고 어서트 합니다.
>>> mock = AsyncMock() >>> async def main(*args, **kwargs): ... await mock(*args, **kwargs) ... >>> asyncio.run(main('foo', bar='bar')) >>> asyncio.run(main('hello')) >>> mock.assert_any_await('foo', bar='bar') >>> mock.assert_any_await('other') Traceback (most recent call last): ... AssertionError: mock('other') await not found
- assert_has_awaits(calls, any_order=False)¶
지정된 호출로 모의 객체가 어웨이트 되었다고 어서트 합니다. 어웨이트에 대해
await_args_list
리스트가 검사됩니다.any_order가 거짓이면 어웨이트는 순차적이어야 합니다. 지정된 어웨이트 전이나 후에 추가 호출이 있을 수 있습니다.
any_order가 참이면 어웨이트 순서와 관계없이 모두
await_args_list
에 나타나야 합니다.>>> mock = AsyncMock() >>> async def main(*args, **kwargs): ... await mock(*args, **kwargs) ... >>> calls = [call("foo"), call("bar")] >>> mock.assert_has_awaits(calls) Traceback (most recent call last): ... AssertionError: Awaits not found. Expected: [call('foo'), call('bar')] Actual: [] >>> asyncio.run(main('foo')) >>> asyncio.run(main('bar')) >>> mock.assert_has_awaits(calls)
- assert_not_awaited()¶
모의 객체가 어웨이트 된 적이 없다고 어서트 합니다.
>>> mock = AsyncMock() >>> mock.assert_not_awaited()
- reset_mock(*args, **kwargs)¶
Mock.reset_mock()
을 참조하십시오. 또한await_count
를 0으로,await_args
를 None으로 설정하고,await_args_list
를 지웁니다.
- await_count¶
모의 객체가 몇 번 어웨이트 되었는지 추적하는 정수.
>>> mock = AsyncMock() >>> async def main(): ... await mock() ... >>> asyncio.run(main()) >>> mock.await_count 1 >>> asyncio.run(main()) >>> mock.await_count 2
- await_args¶
이것은
None
(모의 객체가 어웨이트 되지 않았을 때)이거나 모의 객체가 마지막으로 어웨이트 된 인자입니다.Mock.call_args
와 같게 기능합니다.>>> mock = AsyncMock() >>> async def main(*args): ... await mock(*args) ... >>> mock.await_args >>> asyncio.run(main('foo')) >>> mock.await_args call('foo') >>> asyncio.run(main('bar')) >>> mock.await_args call('bar')
- await_args_list¶
이것은 모의 객체에 대한 모든 어웨이트를 순서대로 나열한 리스트입니다 (따라서 리스트의 길이는 어웨이트 한 횟수입니다). 어웨이트 전에는 빈 리스트입니다.
>>> mock = AsyncMock() >>> async def main(*args): ... await mock(*args) ... >>> mock.await_args_list [] >>> asyncio.run(main('foo')) >>> mock.await_args_list [call('foo')] >>> asyncio.run(main('bar')) >>> mock.await_args_list [call('foo'), call('bar')]
호출¶
모의 객체는 콜러블입니다. 호출은 return_value
어트리뷰트로 설정된 값을 반환합니다. 기본 반환 값은 새로운 Mock 객체입니다; (명시적으로나 Mock을 호출하여) 반환 값에 처음으로 액세스할 때 만들어지지만 - 저장되고 매번 같은 값이 반환됩니다.
객체에 대한 호출은 call_args
와 call_args_list
같은 어트리뷰트로 기록됩니다.
side_effect
가 설정되면 호출이 기록된 후에 호출되므로, side_effect
에서 예외가 발생해도 호출은 여전히 기록됩니다.
호출될 때 모의 객체가 예외를 발생시키는 가장 간단한 방법은 side_effect
를 예외 클래스나 인스턴스로 만드는 것입니다:
>>> m = MagicMock(side_effect=IndexError)
>>> m(1, 2, 3)
Traceback (most recent call last):
...
IndexError
>>> m.mock_calls
[call(1, 2, 3)]
>>> m.side_effect = KeyError('Bang!')
>>> m('two', 'three', 'four')
Traceback (most recent call last):
...
KeyError: 'Bang!'
>>> m.mock_calls
[call(1, 2, 3), call('two', 'three', 'four')]
side_effect
가 함수면 해당 함수가 반환하는 것이 모의 객체에 대한 호출이 반환하는 것입니다. side_effect
함수는 모의 객체와 같은 인자로 호출됩니다. 이를 통해 입력에 따라 호출의 반환 값을 동적으로 변경할 수 있습니다:
>>> def side_effect(value):
... return value + 1
...
>>> m = MagicMock(side_effect=side_effect)
>>> m(1)
2
>>> m(2)
3
>>> m.mock_calls
[call(1), call(2)]
모의 객체가 여전히 기본 반환 값(새로운 모의 객체)을, 또는 설정된 반환 값을, 반환하도록 하려면 두 가지 방법이 있습니다. side_effect
내부에서 mock.return_value
를 반환하거나 DEFAULT
를 반환하십시오:
>>> m = MagicMock()
>>> def side_effect(*args, **kwargs):
... return m.return_value
...
>>> m.side_effect = side_effect
>>> m.return_value = 3
>>> m()
3
>>> def side_effect(*args, **kwargs):
... return DEFAULT
...
>>> m.side_effect = side_effect
>>> m()
3
side_effect
를 제거하고 기본 동작으로 돌아가려면, side_effect
를 None
으로 설정하십시오:
>>> m = MagicMock(return_value=6)
>>> def side_effect(*args, **kwargs):
... return 3
...
>>> m.side_effect = side_effect
>>> m()
3
>>> m.side_effect = None
>>> m()
6
side_effect
는 이터러블 객체일 수도 있습니다. 모의 객체에 대한 반복 호출은 이터러블에서 값을 반환합니다 (이터러블이 소진되고 StopIteration
이 발생할 때까지):
>>> m = MagicMock(side_effect=[1, 2, 3])
>>> m()
1
>>> m()
2
>>> m()
3
>>> m()
Traceback (most recent call last):
...
StopIteration
이터러블의 멤버가 예외이면 반환되는 대신 예외를 발생시킵니다:
>>> iterable = (33, ValueError, 66)
>>> m = MagicMock(side_effect=iterable)
>>> m()
33
>>> m()
Traceback (most recent call last):
...
ValueError
>>> m()
66
어트리뷰트 삭제¶
모의 객체는 요청 시 어트리뷰트를 만듭니다. 이를 통해 모든 형의 객체인 것처럼 가장할 수 있습니다.
모의 객체가 hasattr()
호출에 대해 False
를 반환하거나, 어트리뷰트를 가져올 때 AttributeError
를 발생시키길 원할 수 있습니다. 모의 객체에 spec
으로 객체를 제공하여 그렇게 할 수 있지만, 항상 편리하지는 않습니다.
어트리뷰트를 삭제하여 어트리뷰트를 “차단”합니다. 일단 삭제되면, 어트리뷰트에 액세스할 때 AttributeError
가 발생합니다.
>>> mock = MagicMock()
>>> hasattr(mock, 'm')
True
>>> del mock.m
>>> hasattr(mock, 'm')
False
>>> del mock.f
>>> mock.f
Traceback (most recent call last):
...
AttributeError: f
모의 객체 이름과 이름 어트리뷰트¶
“name”은 Mock
생성자에 대한 인자이므로, 모의 객체가 “name” 어트리뷰트를 가지려면 생성 시 전달할 수 없습니다. 두 가지 대안이 있습니다. 한가지 옵션은 configure_mock()
을 사용하는 것입니다:
>>> mock = MagicMock()
>>> mock.configure_mock(name='my_name')
>>> mock.name
'my_name'
더 간단한 옵션은 모의 객체를 만든 후 단순히 “name” 어트리뷰트를 설정하는 것입니다:
>>> mock = MagicMock()
>>> mock.name = "foo"
모의 객체를 어트리뷰트로 연결하기¶
모의 객체를 다른 모의 객체의 어트리뷰트로 (또는 반환 값으로) 연결하면 그 모의 객체의 “자식”이 됩니다. 자식에 대한 호출은 부모의 method_calls
와 mock_calls
어트리뷰트에 기록됩니다. 이는 자식 모의 객체를 구성한 다음 부모에 연결하는 데 유용합니다. 또는 자식들에 대한 모든 호출을 기록하는 부모에 여러 모의 객체를 연결하고 모의 객체 간의 호출 순서에 대한 어서션을 하는 데 유용합니다:
>>> parent = MagicMock()
>>> child1 = MagicMock(return_value=None)
>>> child2 = MagicMock(return_value=None)
>>> parent.child1 = child1
>>> parent.child2 = child2
>>> child1(1)
>>> child2(2)
>>> parent.mock_calls
[call.child1(1), call.child2(2)]
이에 대한 예외는 모의 객체에 이름이 있는 경우입니다. 어떤 이유로든 원하지 않을 때 “부모가 되는 것(parenting)”을 방지 할 수 있습니다.
>>> mock = MagicMock()
>>> not_a_child = MagicMock(name='not-a-child')
>>> mock.attribute = not_a_child
>>> mock.attribute()
<MagicMock name='not-a-child()' id='...'>
>>> mock.mock_calls
[]
patch()
가 만든 모의 객체에는 자동으로 이름이 지정됩니다. 부모에게 이름을 가진 모의 객체를 연결하려면 attach_mock()
메서드를 사용하십시오:
>>> thing1 = object()
>>> thing2 = object()
>>> parent = MagicMock()
>>> with patch('__main__.thing1', return_value=None) as child1:
... with patch('__main__.thing2', return_value=None) as child2:
... parent.attach_mock(child1, 'child1')
... parent.attach_mock(child2, 'child2')
... child1('one')
... child2('two')
...
>>> parent.mock_calls
[call.child1('one'), call.child2('two')]
패처¶
patch 데코레이터는 데코레이트 하는 함수의 스코프 내에서만 객체를 패치하는 데 사용됩니다. 예외가 발생하더라도 자동으로 패치 해제를 처리합니다. 이러한 함수는 모두 with 문에서 사용될 수 있고, 클래스 데코레이터로도 사용할 수 있습니다.
patch¶
참고
중요한 것은 올바른 이름 공간에서 패치를 수행하는 것입니다. 패치할 곳 절을 참조하십시오.
- unittest.mock.patch(target, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs)¶
patch()
는 함수 데코레이터, 클래스 데코레이터 또는 컨텍스트 관리자 역할을 합니다. 함수 본문이나 with 문 내부에서, target은 new 객체로 패치됩니다. 함수/with 문이 종료될 때 패치가 복구됩니다.new가 생략되면, 대상(target)은 패치된 객체가 비동기 함수이면
AsyncMock
으로, 그렇지 않으면MagicMock
으로 치환됩니다.patch()
가 데코레이터로 사용되고 new가 생략되면, 만들어진 모의 객체는 데코레이트 되는 함수에 대한 추가 인자로 전달됩니다.patch()
가 컨텍스트 관리자로 사용되면 만들어진 모의 객체는 컨텍스트 관리자에 의해 반환됩니다.target은
'package.module.ClassName'
형식의 문자열이어야 합니다. target이 임포트되고 지정된 객체를 new 객체로 치환하므로,patch()
를 호출하는 환경에서 target을 임포트 할 수 있어야 합니다. 데코레이트 하는 시간이 아니라 데코레이트 된 함수가 실행될 때 대상(target)을 임포트 합니다.patch가 여러분을 위해 만든다면 spec과 spec_set 키워드 인자는
MagicMock
으로 전달됩니다.또한
spec=True
나spec_set=True
를 전달하면, patch는 모킹되는 객체를 spec/spec_set 객체로 전달합니다.new_callable을 사용하면 new 객체를 만들기 위해 호출될 다른 클래스나 콜러블 객체를 지정할 수 있습니다. 기본적으로
AsyncMock
이 비동기 함수에 사용되고MagicMock
이 나머지에 사용됩니다.spec의 더 강력한 형태는 autospec입니다.
autospec=True
를 설정하면 치환될 객체의 사양으로 모의 객체가 만들어집니다. 모의 객체의 모든 어트리뷰트는 또한 치환되는 객체의 해당 어트리뷰트의 사양을 갖습니다. 모킹되는 메서드와 함수는 인자를 검사하고 잘못된 서명으로 호출되면TypeError
를 발생시킵니다. 클래스를 치환하는 모의 객체의 경우, 반환 값(‘인스턴스’)은 클래스와 같은 사양을 갖습니다.create_autospec()
함수와 자동 사양을 참조하십시오.autospec=True
대신autospec=some_object
를 전달하여 치환되는 것 대신 임의의 객체를 사양으로 사용할 수 있습니다.기본적으로
patch()
는 존재하지 않는 어트리뷰트를 치환하지 못합니다.create=True
를 전달하고, 어트리뷰트가 존재하지 않으면, 패치된 함수가 호출될 때 patch가 어트리뷰트를 만들고 패치된 함수가 종료된 후 다시 삭제합니다. 이는 프로덕션 코드가 실행 시간에 만드는 어트리뷰트에 대해 테스트를 작성하는 데 유용합니다. 위험할 수 있어서 기본적으로 꺼져있습니다. 이 기능을 켜면 실제로 존재하지 않는 API에 대해 통과하는 테스트를 작성할 수 있습니다!참고
버전 3.5에서 변경: 모듈에 있는 내장(builtins)을 패치하는 경우
create=True
를 전달할 필요가 없습니다, 기본적으로 추가됩니다.패치는
TestCase
클래스 데코레이터로 사용할 수 있습니다. 클래스의 각 테스트 메서드를 데코레이트 하여 작동합니다. 테스트 메서드가 공통 패치 집합을 공유할 때 관리용 코드가 줄어듭니다.patch()
는patch.TEST_PREFIX
로 시작하는 메서드 이름을 조회하는 것으로 테스트를 찾습니다. 기본적으로 이것은'test'
인데,unittest
가 테스트를 찾는 방식과 일치합니다.patch.TEST_PREFIX
를 설정하여 대체 접두사를 지정할 수 있습니다.with 문에서 patch를 컨텍스트 관리자로 사용할 수 있습니다. 여기서 패치는 with 문 다음에 들여쓰기 된 블록에 적용됩니다. “as”를 사용하면 패치된 객체는 “as” 뒤에 오는 이름으로 연결됩니다;
patch()
가 모의 객체를 만들 때 매우 유용합니다.patch()
는 임의의 키워드 인자를 취합니다. 이들은 만들어질 때 패치되는 객체가 비동기이면AsyncMock
으로, 그렇지 않으면Mock
으로, 또는 지정되면 new_callable로 전달됩니다.patch.dict(...)
,patch.multiple(...)
및patch.object(...)
는 대체 사용 사례에 사용할 수 있습니다.
patch()
를 함수 데코레이터로 사용하여, 모의 객체를 만들고 데코레이트 된 함수에 전달합니다:
>>> @patch('__main__.SomeClass')
... def function(normal_argument, mock_class):
... print(mock_class is SomeClass)
...
>>> function(None)
True
클래스를 패치하면 클래스를 MagicMock
인스턴스로 치환합니다. 테스트 대상 코드에서 클래스가 인스턴스 화 되면 사용될 모의 객체의 return_value
가 됩니다.
클래스가 여러 번 인스턴스 화 되면 side_effect
를 사용하여 매번 새 모의 객체를 반환할 수 있습니다. 또는 return_value를 원하는 것으로 설정할 수 있습니다.
패치된 클래스에서 인스턴스의 메서드에 대한 반환 값을 구성하려면 return_value
에서 이를 수행해야 합니다. 예를 들면:
>>> class Class:
... def method(self):
... pass
...
>>> with patch('__main__.Class') as MockClass:
... instance = MockClass.return_value
... instance.method.return_value = 'foo'
... assert Class() is instance
... assert Class().method() == 'foo'
...
spec이나 spec_set을 사용하고 patch()
가 클래스를 대체하고 있다면, 만들어진 모의 객체의 반환 값은 같은 사양을 갖습니다.
>>> Original = Class
>>> patcher = patch('__main__.Class', spec=True)
>>> MockClass = patcher.start()
>>> instance = MockClass()
>>> assert isinstance(instance, Original)
>>> patcher.stop()
new_callable 인자는 생성된 모의 객체의 기본 MagicMock
에 대한 대체 클래스를 사용하려고 할 때 유용합니다. 예를 들어, NonCallableMock
을 사용하려면:
>>> thing = object()
>>> with patch('__main__.thing', new_callable=NonCallableMock) as mock_thing:
... assert thing is mock_thing
... thing()
...
Traceback (most recent call last):
...
TypeError: 'NonCallableMock' object is not callable
또 다른 사용 사례는 객체를 io.StringIO
인스턴스로 교체하는 것입니다:
>>> from io import StringIO
>>> def foo():
... print('Something')
...
>>> @patch('sys.stdout', new_callable=StringIO)
... def test(mock_stdout):
... foo()
... assert mock_stdout.getvalue() == 'Something\n'
...
>>> test()
patch()
가 여러분 대신 모의 객체를 만들 때, 보통 가장 먼저 해야 할 일은 모의 객체를 구성하는 것입니다. 이 구성 중 일부는 patch 호출에서 수행 할 수 있습니다. 호출에 전달하는 임의의 키워드는 만들어진 모의 객체의 어트리뷰트를 설정하는 데 사용됩니다:
>>> patcher = patch('__main__.thing', first='one', second='two')
>>> mock_thing = patcher.start()
>>> mock_thing.first
'one'
>>> mock_thing.second
'two'
만들어진 모의 객체 어트리뷰트뿐만 아니라 자식 모의 객체의 return_value
와 side_effect
와 같은 어트리뷰트도 구성 할 수 있습니다. 키워드 인자로 직접 전달하는 것은 문법적으로 유효하지 않지만, 이것들을 키로 갖는 딕셔너리는 여전히 **
를 사용하여 patch()
호출로 확장될 수 있습니다:
>>> config = {'method.return_value': 3, 'other.side_effect': KeyError}
>>> patcher = patch('__main__.thing', **config)
>>> mock_thing = patcher.start()
>>> mock_thing.method()
3
>>> mock_thing.other()
Traceback (most recent call last):
...
KeyError
기본적으로, 존재하지 않는 모듈의 함수(또는 클래스의 메서드나 어트리뷰트)를 패치하려고 시도하면 AttributeError
로 실패합니다:
>>> @patch('sys.non_existing_attribute', 42)
... def test():
... assert sys.non_existing_attribute == 42
...
>>> test()
Traceback (most recent call last):
...
AttributeError: <module 'sys' (built-in)> does not have the attribute 'non_existing_attribute'
그러나 patch()
호출에 create=True
를 추가하면 이전 예제가 기대한 대로 작동합니다:
>>> @patch('sys.non_existing_attribute', 42, create=True)
... def test(mock_stdout):
... assert sys.non_existing_attribute == 42
...
>>> test()
patch.object¶
- patch.object(target, attribute, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs)¶
모의 객체로 객체(target)의 이름 있는 멤버(attribute)를 패치합니다.
patch.object()
는 데코레이터, 클래스 데코레이터 또는 컨텍스트 관리자로 사용할 수 있습니다. 인자 new, spec, create, spec_set, autospec 및 new_callable은patch()
와 같은 의미입니다.patch()
와 마찬가지로,patch.object()
는 만드는 모의 객체를 구성하기 위해 임의의 키워드 인자를 취합니다.클래스 데코레이터로 사용될 때,
patch.object()
는 감쌀 메서드를 선택하는 데patch.TEST_PREFIX
를 사용합니다.
세 개의 인자나 두 개의 인자로 patch.object()
를 호출 할 수 있습니다. 세 개의 인자 형식은 패치 할 객체, 어트리뷰트 이름 및 어트리뷰트를 대체 할 객체를 취합니다.
두 개의 인자 형식으로 호출하면 대체 객체를 생략하고, 모의 객체가 만들어져 데코레이트 된 함수에 대한 추가 인자로 전달됩니다:
>>> @patch.object(SomeClass, 'class_method')
... def test(mock_method):
... SomeClass.class_method(3)
... mock_method.assert_called_with(3)
...
>>> test()
spec, create 및 patch.object()
에 대한 다른 인자는 patch()
와 같은 의미입니다.
patch.dict¶
- patch.dict(in_dict, values=(), clear=False, **kwargs)¶
딕셔너리나 딕셔너리류 객체를 패치하고, 테스트 후에 딕셔너리를 원래 상태로 복원합니다.
in_dict는 딕셔너리나 컨테이너와 같은 매핑일 수 있습니다. 매핑이면 적어도 가져오기(get), 설정(set) 및 삭제(delete)와 키 이터레이션을 지원해야 합니다.
in_dict는 딕셔너리 이름을 지정하는 문자열일 수도 있으며, 이때는 임포트 해서 가져옵니다.
values는 딕셔너리에 설정할 값의 딕셔너리일 수 있습니다. values는
(key, value)
쌍의 이터러블일 수도 있습니다.clear가 참이면 새 값이 설정되기 전에 딕셔너리가 지워집니다.
딕셔너리에 값을 설정하기 위해 임의의 키워드 인자로
patch.dict()
를 호출할 수도 있습니다.버전 3.8에서 변경:
patch.dict()
는 이제 컨텍스트 관리자로 사용될 때 패치된 딕셔너리를 반환합니다.
patch.dict()
는 컨텍스트 관리자, 데코레이터 또는 클래스 데코레이터로 사용할 수 있습니다:
>>> foo = {}
>>> @patch.dict(foo, {'newkey': 'newvalue'})
... def test():
... assert foo == {'newkey': 'newvalue'}
>>> test()
>>> assert foo == {}
클래스 데코레이터로 사용될 때 patch.dict()
는 감쌀 메서드를 선택하는 데 patch.TEST_PREFIX
(기본값은 'test'
)를 따릅니다:
>>> import os
>>> import unittest
>>> from unittest.mock import patch
>>> @patch.dict('os.environ', {'newkey': 'newvalue'})
... class TestSample(unittest.TestCase):
... def test_sample(self):
... self.assertEqual(os.environ['newkey'], 'newvalue')
테스트에 다른 접두사를 사용하려면, patch.TEST_PREFIX
를 설정하여 패처에 다른 접두사를 알릴 수 있습니다. 값을 변경하는 방법에 대한 자세한 내용은 TEST_PREFIX를 참조하십시오.
patch.dict()
를 사용하여 멤버를 딕셔너리에 추가하고 (또는 단순히 테스트에서 딕셔너리를 변경하고) 테스트가 끝나면 딕셔너리가 복원되도록 할 수 있습니다.
>>> foo = {}
>>> with patch.dict(foo, {'newkey': 'newvalue'}) as patched_foo:
... assert foo == {'newkey': 'newvalue'}
... assert patched_foo == {'newkey': 'newvalue'}
... # You can add, update or delete keys of foo (or patched_foo, it's the same dict)
... patched_foo['spam'] = 'eggs'
...
>>> assert foo == {}
>>> assert patched_foo == {}
>>> import os
>>> with patch.dict('os.environ', {'newkey': 'newvalue'}):
... print(os.environ['newkey'])
...
newvalue
>>> assert 'newkey' not in os.environ
patch.dict()
호출에서 키워드를 사용하여 딕셔너리에 값을 설정할 수 있습니다:
>>> mymodule = MagicMock()
>>> mymodule.function.return_value = 'fish'
>>> with patch.dict('sys.modules', mymodule=mymodule):
... import mymodule
... mymodule.function('some', 'args')
...
'fish'
patch.dict()
can be used with dictionary like objects that aren’t actually
dictionaries. At the very minimum they must support item getting, setting,
deleting and either iteration or membership test. This corresponds to the
magic methods __getitem__()
, __setitem__()
,
__delitem__()
and either __iter__()
or
__contains__()
.
>>> class Container:
... def __init__(self):
... self.values = {}
... def __getitem__(self, name):
... return self.values[name]
... def __setitem__(self, name, value):
... self.values[name] = value
... def __delitem__(self, name):
... del self.values[name]
... def __iter__(self):
... return iter(self.values)
...
>>> thing = Container()
>>> thing['one'] = 1
>>> with patch.dict(thing, one=2, two=3):
... assert thing['one'] == 2
... assert thing['two'] == 3
...
>>> assert thing['one'] == 1
>>> assert list(thing) == ['one']
patch.multiple¶
- patch.multiple(target, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs)¶
한 번의 호출로 여러 패치를 수행합니다. 패치할 객체(객체나 임포트로 객체를 가져올 문자열로)와 패치에 대한 키워드 인자를 취합니다:
with patch.multiple(settings, FIRST_PATCH='one', SECOND_PATCH='two'): ...
patch.multiple()
가 모의 객체를 만들기를 원하면DEFAULT
를 값으로 사용하십시오. 이 경우 만들어진 모의 객체는 키워드로 데코레이트 된 함수로 전달되며,patch.multiple()
이 컨텍스트 관리자로 사용될 때는 딕셔너리가 반환됩니다.patch.multiple()
은 데코레이터, 클래스 데코레이터 또는 컨텍스트 관리자로 사용할 수 있습니다. spec, spec_set, create, autospec 및 new_callable 인자는patch()
와 같은 의미입니다. 이 인자는patch.multiple()
이 수행한 모든 패치에 적용됩니다.클래스 데코레이터로 사용될 때
patch.multiple()
은 감쌀 메서드를 선택하는 데patch.TEST_PREFIX
를 사용합니다.
patch.multiple()
가 모의 객체를 만들기를 원하면 DEFAULT
를 값으로 사용할 수 있습니다. patch.multiple()
을 데코레이터로 사용하면 만들어진 모의 객체가 키워드로 데코레이트 된 함수에 전달됩니다.
>>> thing = object()
>>> other = object()
>>> @patch.multiple('__main__', thing=DEFAULT, other=DEFAULT)
... def test_function(thing, other):
... assert isinstance(thing, MagicMock)
... assert isinstance(other, MagicMock)
...
>>> test_function()
patch.multiple()
은 다른 patch
데코레이터와 중첩될 수 있지만, 키워드로 전달된 인자를 patch()
가 만든 모든 표준 인자들 뒤에 넣습니다:
>>> @patch('sys.exit')
... @patch.multiple('__main__', thing=DEFAULT, other=DEFAULT)
... def test_function(mock_exit, other, thing):
... assert 'other' in repr(other)
... assert 'thing' in repr(thing)
... assert 'exit' in repr(mock_exit)
...
>>> test_function()
patch.multiple()
가 컨텍스트 관리자로 사용되면, 컨텍스트 관리자가 반환한 값은 만들어진 모의 객체 이름을 키로 갖는 딕셔너리입니다:
>>> with patch.multiple('__main__', thing=DEFAULT, other=DEFAULT) as values:
... assert 'other' in repr(values['other'])
... assert 'thing' in repr(values['thing'])
... assert values['thing'] is thing
... assert values['other'] is other
...
패처 메서드: start와 stop¶
모든 패처에는 start()
와 stop()
메서드가 있습니다. 이를 통해 setUp
메서드나 데코레이터를 중첩하거나 with 문을 사용하지 않고 여러 패치를 수행하려는 곳에서 패치를 수행하는 것이 더 간단해집니다.
이것들을 사용하려면 patch()
, patch.object()
또는 patch.dict()
를 정상적으로 호출하고 반환된 patcher
객체에 대한 참조를 유지하십시오. 그런 다음 start()
를 호출하여 패치를 제자리에 놓고 stop()
을 사용하여 패치를 취소할 수 있습니다.
patch()
를 사용하여 모의 객체를 만들면 patcher.start
호출로 반환됩니다.
>>> patcher = patch('package.module.ClassName')
>>> from package import module
>>> original = module.ClassName
>>> new_mock = patcher.start()
>>> assert module.ClassName is not original
>>> assert module.ClassName is new_mock
>>> patcher.stop()
>>> assert module.ClassName is original
>>> assert module.ClassName is not new_mock
일반적인 사용 사례는 TestCase
의 setUp
메서드에서 여러 패치를 수행하는 것입니다:
>>> class MyTest(unittest.TestCase):
... def setUp(self):
... self.patcher1 = patch('package.module.Class1')
... self.patcher2 = patch('package.module.Class2')
... self.MockClass1 = self.patcher1.start()
... self.MockClass2 = self.patcher2.start()
...
... def tearDown(self):
... self.patcher1.stop()
... self.patcher2.stop()
...
... def test_something(self):
... assert package.module.Class1 is self.MockClass1
... assert package.module.Class2 is self.MockClass2
...
>>> MyTest('test_something').run()
조심
이 기법을 사용하는 경우 stop
을 호출하여 패치가 “실행 취소” 되도록 해야 합니다. setUp
에서 예외가 발생하면 tearDown
이 호출되지 않기 때문에, 이것은 생각보다 까다로울 수 있습니다. unittest.TestCase.addCleanup()
은 이것을 더 쉽게 만듭니다:
>>> class MyTest(unittest.TestCase):
... def setUp(self):
... patcher = patch('package.module.Class')
... self.MockClass = patcher.start()
... self.addCleanup(patcher.stop)
...
... def test_something(self):
... assert package.module.Class is self.MockClass
...
추가 보너스로 더는 patcher
객체에 대한 참조를 유지할 필요가 없습니다.
patch.stopall()
을 사용하여 시작된 모든 패치를 중지할 수도 있습니다.
- patch.stopall()¶
모든 활성 패치를 중지합니다.
start
로 시작한 패치만 중지합니다.
내장 패치¶
모듈 내의 어떤 내장(builtins)도 패치 할 수 있습니다. 다음 예제는 내장 ord()
를 패치합니다:
>>> @patch('__main__.ord')
... def test(mock_ord):
... mock_ord.return_value = 101
... print(ord('c'))
...
>>> test()
101
TEST_PREFIX¶
모든 패처를 클래스 데코레이터로 사용할 수 있습니다. 이런 식으로 사용하면 클래스의 모든 테스트 메서드를 감쌉니다. 패처는 'test'
로 시작하는 메서드를 테스트 메서드로 인식합니다. 이것은 unittest.TestLoader
가 기본적으로 테스트 메서드를 찾는 것과 같은 방법입니다.
테스트에 다른 접두사를 사용하고 싶을 수도 있습니다. patch.TEST_PREFIX
를 설정하여 다른 접두사를 패처에 알릴 수 있습니다:
>>> patch.TEST_PREFIX = 'foo'
>>> value = 3
>>>
>>> @patch('__main__.value', 'not three')
... class Thing:
... def foo_one(self):
... print(value)
... def foo_two(self):
... print(value)
...
>>>
>>> Thing().foo_one()
not three
>>> Thing().foo_two()
not three
>>> value
3
패치 데코레이터 중첩하기¶
여러 패치를 수행하려면 단순히 데코레이터를 쌓으면 됩니다.
이 패턴을 사용하여 여러 패치 데코레이터를 쌓을 수 있습니다:
>>> @patch.object(SomeClass, 'class_method')
... @patch.object(SomeClass, 'static_method')
... def test(mock1, mock2):
... assert SomeClass.static_method is mock1
... assert SomeClass.class_method is mock2
... SomeClass.static_method('foo')
... SomeClass.class_method('bar')
... return mock1, mock2
...
>>> mock1, mock2 = test()
>>> mock1.assert_called_once_with('foo')
>>> mock2.assert_called_once_with('bar')
데코레이터는 아래에서 위쪽으로 적용됨에 유의하십시오. 이것은 파이썬이 데코레이터를 적용하는 표준 방식입니다. 생성된 모의 객체가 테스트 함수에 전달되는 순서는 이 순서와 일치합니다.
패치할 곳¶
patch()
는 name이 가리키는 객체를 다른 객체로 (임시로) 변경하여 작동합니다. 개별 객체를 가리키는 많은 이름이 있을 수 있어서, 패치가 작동하려면 테스트 대상 시스템에서 사용하는 이름을 패치해야 합니다.
기본 원칙은 객체가 조회되는 곳을 패치하는 것입니다. 이것은 정의된 곳과 반드시 같은 곳일 필요는 없습니다. 몇 가지 예가 이를 명확히 하는 데 도움이 됩니다.
테스트하려는 프로젝트가 다음 구조로 되어 있다고 가정하십시오:
a.py
-> Defines SomeClass
b.py
-> from a import SomeClass
-> some_function instantiates SomeClass
이제 some_function
을 테스트하고 싶지만, patch()
를 사용하여 SomeClass
를 모킹하고 싶습니다. 문제는 모듈 b를 임포트 할 때 모듈 a에서 SomeClass
를 임포트해야 한다는 것입니다. patch()
를 사용하여 a.SomeClass
를 모킹하면 테스트에 영향을 미치지 않습니다; 모듈 b는 이미 실제 SomeClass
에 대한 참조를 가지고 있으며 패치가 효과가 없는 것처럼 보입니다.
핵심은 SomeClass
가 사용되는 곳(또는 그것을 조회하는 곳)을 패치하는 것입니다. 이 경우 some_function
은 우리가 임포트 한 모듈 b에서 SomeClass
를 조회합니다. 패치는 다음과 같아야 합니다:
@patch('b.SomeClass')
하지만, from a import SomeClass
대신 모듈 b가 import a
를 수행하고 some_function
이 a.SomeClass
를 사용하는 대체 시나리오를 생각해보십시오. 이 두 가지 임포트 형식은 모두 일반적입니다. 이 경우 패치하려는 클래스가 모듈에서 조회되므로 대신 a.SomeClass
를 패치해야 합니다:
@patch('a.SomeClass')
디스크립터와 프락시 객체 패치하기¶
Both patch and patch.object correctly patch and restore descriptors: class methods, static methods and properties. You should patch these on the class rather than an instance. They also work with some objects that proxy attribute access, like the django settings object.
MagicMock과 매직 메서드 지원¶
매직 메서드 모킹하기¶
Mock
supports mocking the Python protocol methods, also known as
“magic methods”. This allows mock objects to replace
containers or other objects that implement Python protocols.
매직 메서드는 일반 메서드와는 다르게 조회되므로 [2], 이 지원은 특별히 구현되었습니다. 즉, 특정 매직 메서드만 지원됩니다. 지원되는 목록에 이들이 거의 모두 포함됩니다. 누락된 것이 있으면 알려주십시오.
관심 있는 메서드를 함수나 모의 객체 인스턴스로 설정하여 매직 메서드를 모킹합니다. 함수를 사용하면 반드시 self
를 첫 번째 인자로 취해야 합니다 [3].
>>> def __str__(self):
... return 'fooble'
...
>>> mock = Mock()
>>> mock.__str__ = __str__
>>> str(mock)
'fooble'
>>> mock = Mock()
>>> mock.__str__ = Mock()
>>> mock.__str__.return_value = 'fooble'
>>> str(mock)
'fooble'
>>> mock = Mock()
>>> mock.__iter__ = Mock(return_value=iter([]))
>>> list(mock)
[]
이것의 한 가지 사용 사례는 with
문에서 컨텍스트 관리자로 사용되는 객체를 모킹하는 것입니다:
>>> mock = Mock()
>>> mock.__enter__ = Mock(return_value='foo')
>>> mock.__exit__ = Mock(return_value=False)
>>> with mock as m:
... assert m == 'foo'
...
>>> mock.__enter__.assert_called_with()
>>> mock.__exit__.assert_called_with(None, None, None)
매직 메서드 호출은 method_calls
에는 나타나지 않지만, mock_calls
에 기록됩니다.
참고
spec 키워드 인자를 사용하여 모의 객체를 만들면 spec에 없는 매직 메서드를 설정하려고 시도할 때 AttributeError
가 발생합니다.
지원되는 매직 메서드의 전체 목록은 다음과 같습니다:
__hash__
,__sizeof__
,__repr__
및__str__
__dir__
,__format__
및__subclasses__
__round__
,__floor__
,__trunc__
및__ceil__
비교:
__lt__
,__gt__
,__le__
,__ge__
,__eq__
및__ne__
컨테이너 메서드:
__getitem__
,__setitem__
,__delitem__
,__contains__
,__len__
,__iter__
,__reversed__
및__missing__
컨텍스트 관리자:
__enter__
,__exit__
,__aenter__
및__aexit__
단항 숫자 메서드:
__neg__
,__pos__
및__invert__
The numeric methods (including right hand and in-place variants):
__add__
,__sub__
,__mul__
,__matmul__
,__truediv__
,__floordiv__
,__mod__
,__divmod__
,__lshift__
,__rshift__
,__and__
,__xor__
,__or__
, and__pow__
숫자 변환 메서드:
__complex__
,__int__
,__float__
및__index__
디스크립터 메서드:
__get__
,__set__
및__delete__
피클링:
__reduce__
,__reduce_ex__
,__getinitargs__
,__getnewargs__
,__getstate__
및__setstate__
파일 시스템 경로 표현:
__fspath__
비동기 이터레이션 메서드:
__aiter__
와__anext__
버전 3.8에서 변경: os.PathLike.__fspath__()
에 대한 지원이 추가되었습니다.
버전 3.8에서 변경: __aenter__
, __aexit__
, __aiter__
및 __anext__
에 대한 지원이 추가되었습니다.
다음과 같은 메서드가 존재하지만, 모의 객체가 사용 중이거나, 동적으로 설정할 수 없거나, 문제를 일으킬 수 있어서 지원되지 않습니다:
__getattr__
,__setattr__
,__init__
및__new__
__prepare__
,__instancecheck__
,__subclasscheck__
,__del__
매직 모의 객체¶
두 가지 MagicMock
변형이 있습니다: MagicMock
과 NonCallableMagicMock
.
- class unittest.mock.MagicMock(*args, **kw)¶
MagicMock
is a subclass ofMock
with default implementations of most of the magic methods. You can useMagicMock
without having to configure the magic methods yourself.생성자 매개 변수는
Mock
과 같은 의미입니다.spec이나 spec_set 인자를 사용하면 오직 사양에 존재하는 매직 메서드만 만들어집니다.
- class unittest.mock.NonCallableMagicMock(*args, **kw)¶
콜러블이 아닌
MagicMock
버전.생성자 매개 변수는 콜러블이 아닌 모의 객체에 의미가 없는 return_value와 side_effect를 제외하고
MagicMock
과 같은 의미입니다.
매직 메서드는 MagicMock
객체로 설정되므로, 일반적인 방법으로 구성하고 사용할 수 있습니다:
>>> mock = MagicMock()
>>> mock[3] = 'fish'
>>> mock.__setitem__.assert_called_with(3, 'fish')
>>> mock.__getitem__.return_value = 'result'
>>> mock[2]
'result'
기본적으로 많은 프로토콜 메서드는 특정 형의 객체를 반환하도록 요구합니다. 이러한 메서드는 기본 반환 값으로 사전 구성되어 있어서, 반환 값에 관심이 없을 때 아무 조처를 하지 않아도 사용할 수 있습니다. 기본값을 변경하고 싶으면, 여전히 반환 값을 수동으로 설정할 수 있습니다.
메서드와 기본값:
__lt__
:NotImplemented
__gt__
:NotImplemented
__le__
:NotImplemented
__ge__
:NotImplemented
__int__
:1
__contains__
:False
__len__
:0
__iter__
:iter([])
__exit__
:False
__aexit__
:False
__complex__
:1j
__float__
:1.0
__bool__
:True
__index__
:1
__hash__
: 모의 객체의 기본 hash__str__
: 모의 객체의 기본 str__sizeof__
: 모의 객체의 기본 sizeof
예를 들면:
>>> mock = MagicMock()
>>> int(mock)
1
>>> len(mock)
0
>>> list(mock)
[]
>>> object() in mock
False
The two equality methods, __eq__()
and __ne__()
, are special.
They do the default equality comparison on identity, using the
side_effect
attribute, unless you change their return value to
return something else:
>>> MagicMock() == 3
False
>>> MagicMock() != 3
True
>>> mock = MagicMock()
>>> mock.__eq__.return_value = True
>>> mock == 3
True
MagicMock.__iter__()
의 반환 값은 임의의 이터러블 객체일 수 있으며 이터레이터일 필요는 없습니다:
>>> mock = MagicMock()
>>> mock.__iter__.return_value = ['a', 'b', 'c']
>>> list(mock)
['a', 'b', 'c']
>>> list(mock)
['a', 'b', 'c']
반환 값이 이터레이터면, 일단 이터레이트 하면 이를 소진하고 후속 이터레이션은 빈 목록을 줍니다:
>>> mock.__iter__.return_value = iter(['a', 'b', 'c'])
>>> list(mock)
['a', 'b', 'c']
>>> list(mock)
[]
MagicMock
에는 불분명하고 쓸모없는 일부를 제외하고 지원되는 모든 매직 메서드가 구성되어 있습니다. 원한다면 여전히 설정할 수 있습니다.
MagicMock
에서 지원되지만, 기본적으로 설정되지 않는 매직 메서드는 다음과 같습니다:
__subclasses__
__dir__
__format__
__get__
,__set__
및__delete__
__reversed__
와__missing__
__reduce__
,__reduce_ex__
,__getinitargs__
,__getnewargs__
,__getstate__
및__setstate__
__getformat__
매직 메서드는 인스턴스가 아닌 클래스에서 조회되어야 합니다. 다른 버전의 파이썬은 이 규칙을 적용하는 데 일관적이지 않습니다. 지원되는 프로토콜 메서드는 지원되는 모든 버전의 파이썬에서 작동해야 합니다.
이 함수는 기본적으로 클래스에 연결되어 있지만, 각 Mock
인스턴스는 다른 것들과 격리되어 있습니다.
도우미¶
sentinel¶
- unittest.mock.sentinel¶
sentinel
객체는 테스트에 고유한(unique) 객체를 제공하는 편리한 방법을 제공합니다.어트리뷰트는 이름으로 어트리뷰트에 액세스할 때 요청에 따라 만들어집니다. 같은 어트리뷰트에 액세스하면 항상 같은 객체가 반환됩니다. 반환된 객체는 테스트 실패 메시지를 읽을 수 있도록 적절한 repr을 갖습니다.
때로 테스트할 때 특정 객체가 다른 메서드에 대한 인자로 전달되거나 반환되는지 테스트해야 할 때가 있습니다. 이것을 테스트하기 위해 이름 붙은 sentinel 객체를 만드는 것이 일반적일 수 있습니다. sentinel
은 이와 같은 객체의 아이덴티티를 만들고 테스트하는 편리한 방법을 제공합니다.
이 예에서는 method
를 sentinel.some_object
를 반환하도록 몽키 패치합니다:
>>> real = ProductionClass()
>>> real.method = Mock(name="method")
>>> real.method.return_value = sentinel.some_object
>>> result = real.method()
>>> assert result is sentinel.some_object
>>> result
sentinel.some_object
DEFAULT¶
- unittest.mock.DEFAULT¶
DEFAULT
객체는 미리 만들어진 sentinel(실제로sentinel.DEFAULT
)입니다.side_effect
함수에서 일반 반환 값을 사용해야 함을 나타내는 데 사용할 수 있습니다.
call¶
- unittest.mock.call(*args, **kwargs)¶
call()
은call_args
,call_args_list
,mock_calls
및method_calls
와 비교할 때, 더 간단한 어서션을 만들기 위한 도우미 객체입니다.call()
은assert_has_calls()
와 함께 사용할 수도 있습니다.>>> m = MagicMock(return_value=None) >>> m(1, 2, a='foo', b='bar') >>> m() >>> m.call_args_list == [call(1, 2, a='foo', b='bar'), call()] True
- call.call_list()¶
여러 호출을 나타내는 호출 객체의 경우,
call_list()
는 마지막 호출뿐만 아니라 모든 중간 호출의 목록을 반환합니다.
call_list
는 “연쇄 호출(chained calls)”에 대한 어서션을 만드는 데 특히 유용합니다. 연쇄 호출은 한 줄의 코드에 있는 여러 번의 호출입니다. 이로 인해 모의 객체의 mock_calls
에 여러 항목이 생성됩니다. 호출 시퀀스를 수동으로 구성하는 것은 지루할 수 있습니다.
call_list()
는 같은 연쇄 호출에서 호출 시퀀스를 구성 할 수 있습니다.:
>>> m = MagicMock()
>>> m(1).method(arg='foo').other('bar')(2.0)
<MagicMock name='mock().method().other()()' id='...'>
>>> kall = call(1).method(arg='foo').other('bar')(2.0)
>>> kall.call_list()
[call(1),
call().method(arg='foo'),
call().method().other('bar'),
call().method().other()(2.0)]
>>> m.mock_calls == kall.call_list()
True
call
객체는 구성 방식에 따라 (위치 인자, 키워드 인자)나 (이름, 위치 인자, 키워드 인자)의 튜플입니다. 이것들을 직접 만들 때 특별히 흥미롭지는 않지만, Mock.call_args
, Mock.call_args_list
및 Mock.mock_calls
어트리뷰트에 있는 call
객체는 포함된 개별 인자를 얻기 위해 검사될 수 있습니다.
Mock.call_args
와 Mock.call_args_list
에 있는 call
객체는 (위치 인자, 키워드 인자)의 2-튜플이지만, Mock.mock_calls
에 있는 call
객체는, 여러분이 직접 생성하는 객체와 함께, (이름, 위치 인자, 키워드 인자)의 3-튜플입니다.
이들의 “튜플성(tupleness)”을 사용하여 더 복잡한 검사와 어서션을 위해 개별 인자를 가져올 수 있습니다. 위치 인자는 튜플(위치 인자가 없으면 비어있는 튜플)이고 키워드 인자는 딕셔너리입니다:
>>> m = MagicMock(return_value=None)
>>> m(1, 2, 3, arg='one', arg2='two')
>>> kall = m.call_args
>>> kall.args
(1, 2, 3)
>>> kall.kwargs
{'arg': 'one', 'arg2': 'two'}
>>> kall.args is kall[0]
True
>>> kall.kwargs is kall[1]
True
>>> m = MagicMock()
>>> m.foo(4, 5, 6, arg='two', arg2='three')
<MagicMock name='mock.foo()' id='...'>
>>> kall = m.mock_calls[0]
>>> name, args, kwargs = kall
>>> name
'foo'
>>> args
(4, 5, 6)
>>> kwargs
{'arg': 'two', 'arg2': 'three'}
>>> name is m.mock_calls[0][0]
True
create_autospec¶
- unittest.mock.create_autospec(spec, spec_set=False, instance=False, **kwargs)¶
다른 객체를 사양으로 사용하여 모의 객체를 만듭니다. 모의 객체 어트리뷰트는 spec 객체의 해당 어트리뷰트를 사양으로 사용합니다.
모킹되는 함수나 메서드는 올바른 서명으로 호출되도록 인자를 점검합니다.
spec_set이
True
이면 사양 객체에 존재하지 않는 어트리뷰트를 설정하려는 시도는AttributeError
를 발생시킵니다.클래스가 사양으로 사용되면 모의 객체의 반환 값(클래스의 인스턴스)은 같은 사양을 갖습니다.
instance=True
를 전달하여 클래스를 인스턴스 객체의 사양으로 사용할 수 있습니다. 반환된 모의 객체는 모의 객체의 인스턴스가 콜러블일 때만 콜러블입니다.create_autospec()
은 또한 만들어진 모의 객체의 생성자에 전달되는 임의의 키워드 인자를 취합니다.
create_autospec()
과 patch()
에 대한 autospec 인자로 자동 사양을 사용하는 방법에 대한 예는 자동 사양을 참조하십시오.
버전 3.8에서 변경: 대상이 비동기 함수이면 create_autospec()
은 이제 AsyncMock
을 반환합니다.
ANY¶
- unittest.mock.ANY¶
때로는 모의 객체 호출에서 인자의 일부에 대한 어서션을 만들 필요가 있지만, 일부 인자에는 신경 쓰지 않거나 call_args
에서 개별적으로 꺼내어 더 복잡한 어서션을 만들고 싶을 수도 있습니다.
특정 인자를 무시하려면 모든 것과 같다고 비교되는 객체를 전달할 수 있습니다. assert_called_with()
와 assert_called_once_with()
에 대한 호출은 전달된 내용과 관계없이 성공합니다.
>>> mock = Mock(return_value=None)
>>> mock('foo', bar=object())
>>> mock.assert_called_once_with('foo', bar=ANY)
ANY
는 mock_calls
와 같은 호출 리스트와 비교할 때도 사용할 수 있습니다.:
>>> m = MagicMock(return_value=None)
>>> m(1)
>>> m(1, 2)
>>> m(object())
>>> m.mock_calls == [call(1), call(1, 2), ANY]
True
ANY
is not limited to comparisons with call objects and so
can also be used in test assertions:
class TestStringMethods(unittest.TestCase):
def test_split(self):
s = 'hello world'
self.assertEqual(s.split(), ['hello', ANY])
FILTER_DIR¶
- unittest.mock.FILTER_DIR¶
FILTER_DIR
is a module level variable that controls the way mock objects
respond to dir()
. The default is True
,
which uses the filtering described below, to only show useful members. If you
dislike this filtering, or need to switch it off for diagnostic purposes, then
set mock.FILTER_DIR = False
.
필터링을 켜면, dir(some_mock)
는 유용한 어트리뷰트만 표시하고 일반적으로 표시되지 않는 동적으로 만들어진 어트리뷰트를 포함합니다. spec(또는 물론 autospec)으로 모의 객체를 만들었으면, 아직 액세스하지 않았다 할지라도 원본의 모든 어트리뷰트가 표시됩니다:
>>> dir(Mock())
['assert_any_call',
'assert_called',
'assert_called_once',
'assert_called_once_with',
'assert_called_with',
'assert_has_calls',
'assert_not_called',
'attach_mock',
...
>>> from urllib import request
>>> dir(Mock(spec=request))
['AbstractBasicAuthHandler',
'AbstractDigestAuthHandler',
'AbstractHTTPHandler',
'BaseHandler',
...
Mock
에 대해 dir()
을 호출한 결과에서 그다지 유용하지 않은 (모킹되는 대상이 아닌 Mock
전용) 밑줄과 이중 밑줄 접두어 어트리뷰트가 필터링 되었습니다. 이 동작이 마음에 들지 않으면 모듈 수준 스위치 FILTER_DIR
를 설정하여 끌 수 있습니다.:
>>> from unittest import mock
>>> mock.FILTER_DIR = False
>>> dir(mock.Mock())
['_NonCallableMock__get_return_value',
'_NonCallableMock__get_side_effect',
'_NonCallableMock__return_value_doc',
'_NonCallableMock__set_return_value',
'_NonCallableMock__set_side_effect',
'__call__',
'__class__',
...
Alternatively you can just use vars(my_mock)
(instance members) and
dir(type(my_mock))
(type members) to bypass the filtering irrespective of
mock.FILTER_DIR
.
mock_open¶
- unittest.mock.mock_open(mock=None, read_data=None)¶
open()
의 사용을 대체하기 위한 모의 객체를 만드는 도우미 함수. 직접 호출되거나 컨텍스트 관리자로 사용되는open()
에 대해 작동합니다.mock 인자는 구성할 모의 객체입니다.
None
(기본값)이면 표준 파일 핸들에서 사용 가능한 메서드나 어트리뷰트로 API가 제한된MagicMock
이 만들어집니다.read_data는 파일 핸들의
read()
,readline()
및readlines()
메서드가 반환할 문자열입니다. 이러한 메서드를 호출하면 read_data에서 데이터가 고갈될 때까지 데이터를 가져옵니다. 이러한 메서드의 모의 객체는 매우 단순합니다: mock이 호출될 때마다 read_data는 처음으로 되감깁니다. 테스트 되는 코드에 공급하는 데이터를 더 세밀하게 제어하려면 이 모의 객체를 스스로 사용자 정의해야 합니다. 이것으로 불충분하면, PyPI의 메모리 내 파일 시스템 패키지 중 하나가 테스트를 위한 진짜 같은 파일 시스템을 제공할 수 있습니다.버전 3.4에서 변경:
readline()
과readlines()
지원이 추가되었습니다.read()
의 모의 객체는 호출마다 read_data를 반환하는 대신 소비하도록 변경되었습니다.버전 3.5에서 변경: read_data는 이제 mock을 호출할 때마다 재설정됩니다.
버전 3.8에서 변경: Added
__iter__()
to implementation so that iteration (such as in for loops) correctly consumes read_data.
open()
을 컨텍스트 관리자로 사용하는 것은 파일 핸들이 올바르게 닫히도록 보장하는 좋은 방법이고 점차 일반화되고 있습니다:
with open('/some/path', 'w') as f:
f.write('something')
The issue is that even if you mock out the call to open()
it is the
returned object that is used as a context manager (and has __enter__()
and
__exit__()
called).
MagicMock
으로 컨텍스트 관리자를 모킹하는 것은 도우미 함수가 유용할 만큼 충분히 일반적입니다.
>>> m = mock_open()
>>> with patch('__main__.open', m):
... with open('foo', 'w') as h:
... h.write('some stuff')
...
>>> m.mock_calls
[call('foo', 'w'),
call().__enter__(),
call().write('some stuff'),
call().__exit__(None, None, None)]
>>> m.assert_called_once_with('foo', 'w')
>>> handle = m()
>>> handle.write.assert_called_once_with('some stuff')
그리고 파일을 읽기 위해서는:
>>> with patch('__main__.open', mock_open(read_data='bibble')) as m:
... with open('foo') as h:
... result = h.read()
...
>>> m.assert_called_once_with('foo')
>>> assert result == 'bibble'
자동 사양¶
자동 사양은 기존의 spec
기능을 기반으로 합니다. 모의 객체 api를 원본 객체(사양)의 api로 제한하지만, 재귀적(게으르게(lazily) 구현되었습니다)이라서 모의 객체의 어트리뷰트는 사양의 어트리뷰트와 같은 api만 갖습니다. 또한 모킹된 함수 / 메서드는 원본과 같은 호출 서명을 가지므로 잘못 호출되면 TypeError
를 발생시킵니다.
자동 사양이 작동하는 방식을 설명하기 전에, 이것이 필요한 이유는 이렇습니다.
Mock
은 매우 강력하고 유연한 객체이지만, 테스트 대상 시스템에서 객체를 모킹할 때 두 가지 결함이 있습니다. 이러한 결함 중 하나는 Mock
api에만 해당하며 다른 하나는 모의 객체 사용에 대한 보다 일반적인 문제입니다.
먼저 Mock
과 관련된 문제입니다. Mock
에는 assert_called_with()
와 assert_called_once_with()
라는 매우 편리한 두 가지 어서션 메서드가 있습니다.
>>> mock = Mock(name='Thing', return_value=None)
>>> mock(1, 2, 3)
>>> mock.assert_called_once_with(1, 2, 3)
>>> mock(1, 2, 3)
>>> mock.assert_called_once_with(1, 2, 3)
Traceback (most recent call last):
...
AssertionError: Expected 'mock' to be called once. Called 2 times.
모의 객체는 요청 시 어트리뷰트를 자동 생성하고, 임의의 인자로 어트리뷰트를 호출하도록 허락합니다, 이러한 어서트 메서드 중 하나의 철자를 틀리면 어서션이 사라집니다:
>>> mock = Mock(name='Thing', return_value=None)
>>> mock(1, 2, 3)
>>> mock.assret_called_once_with(4, 5, 6) # Intentional typo!
오타로 인해 테스트가 조용히 잘못 통과할 수 있습니다.
두 번째 문제는 모킹에 더 일반적입니다. 멤버 이름 등을 변경하는 등 일부 코드를 리팩토링하면, 여전히 예전 api를 사용하는 코드에 대한 테스트는 실제 객체 대신 모의 객체를 사용하면 모두 통과합니다. 이것은 코드가 손상되어도 테스트를 모두 통과 할 수 있다는 뜻입니다.
이것이 단위 테스트뿐만 아니라 통합 테스트가 필요한 또 다른 이유입니다. 모든 것을 분리해서 테스트하는 것은 괜찮고 멋지지만, 단위들이 어떻게 “서로 연결되어” 있는지 테스트하지 않으면 테스트가 발견할 수도 있을 버그에 대한 여지가 여전히 많습니다.
mock
은 이미 이에 도움이 되는 기능인 사양(speccing)을 제공합니다. 모의 객체에 클래스나 인스턴스를 spec
으로 사용하면, 실제 클래스에 존재하는 모의 객체 어트리뷰트에만 액세스 할 수 있습니다:
>>> from urllib import request
>>> mock = Mock(spec=request.Request)
>>> mock.assret_called_with # Intentional typo!
Traceback (most recent call last):
...
AttributeError: Mock object has no attribute 'assret_called_with'
사양은 모의 객체 자체에만 적용되므로, 모의 객체의 메서드와 관계된 문제는 여전히 있습니다:
>>> mock.has_data()
<mock.Mock object at 0x...>
>>> mock.has_data.assret_called_with() # Intentional typo!
자동 사양은 이 문제를 해결합니다. autospec=True
를 patch()
/ patch.object()
로 전달하거나 create_autospec()
함수를 사용하여 사양이 있는 모의 객체를 만들 수 있습니다. autospec=True
인자를 patch()
에 사용하면 대체 중인 객체가 사양 객체로 사용됩니다. 사양화(speccing)는 “게으르게(lazily)” 수행되므로 (모의 객체의 어트리뷰트에 액세스할 때 사양이 만들어집니다) 성능이 크게 저하되지 않고도 매우 복잡하거나 깊이 중첩된 객체(가령 모듈을 임포트 하는 모듈을 임포트 하는 모듈)와 함께 사용할 수 있습니다.
사용 예는 다음과 같습니다:
>>> from urllib import request
>>> patcher = patch('__main__.request', autospec=True)
>>> mock_request = patcher.start()
>>> request is mock_request
True
>>> mock_request.Request
<MagicMock name='request.Request' spec='Request' id='...'>
request.Request
에 spec이 있음을 알 수 있습니다. request.Request
는 생성자에서 두 개의 인자를 취합니다 (하나는 self입니다). 잘못 호출하면 이렇게 됩니다:
>>> req = request.Request()
Traceback (most recent call last):
...
TypeError: <lambda>() takes at least 2 arguments (1 given)
사양은 인스턴스 화 된 클래스(즉, 사양화된 모의 객체의 반환 값)에도 적용됩니다:
>>> req = request.Request('foo')
>>> req
<NonCallableMagicMock name='request.Request()' spec='Request' id='...'>
Request
객체는 콜러블이 아니므로, 모킹된 request.Request
의 인스턴스 화의 반환 값은 콜러블이 아닌 모의 객체입니다. 사양이 적용되면 어서션에 오타가 있을 때 올바른 에러를 발생시킵니다:
>>> req.add_header('spam', 'eggs')
<MagicMock name='request.Request().add_header()' id='...'>
>>> req.add_header.assret_called_with # Intentional typo!
Traceback (most recent call last):
...
AttributeError: Mock object has no attribute 'assret_called_with'
>>> req.add_header.assert_called_with('spam', 'eggs')
많은 경우 단지 기존 patch()
호출에 autospec=True
를 추가하면 오타와 api 변경으로 인한 버그로부터 보호할 수 있습니다.
patch()
를 통해 autospec을 사용하는 것뿐만 아니라 자동 사양 모의 객체를 직접 만들기 위한 create_autospec()
도 있습니다:
>>> from urllib import request
>>> mock_request = create_autospec(request)
>>> mock_request.Request('foo', 'bar')
<NonCallableMagicMock name='mock.Request()' spec='Request' id='...'>
그러나 경고와 제한이 없는 것은 아니기 때문에 기본 동작이 아닙니다. 사양 객체에서 사용 가능한 어트리뷰트를 알기 위해 autospec은 사양을 검사(어트리뷰트를 액세스합니다)해야 합니다. 모의 객체 어트리뷰트를 탐색할 때 원본 객체의 대응하는 탐색이 수면 아래에서 발생합니다. 사양 객체 중 어느 하나가 코드 실행을 트리거 할 수 있는 프로퍼티나 디스크립터를 갖는 경우 자동 사양을 사용하지 못할 수 있습니다. 반면에, 내부 검사가 안전하도록 객체를 설계하는 것이 훨씬 좋습니다 [4].
A more serious problem is that it is common for instance attributes to be
created in the __init__()
method and not to exist on the class at all.
autospec can’t know about any dynamically created attributes and restricts
the api to visible attributes.
>>> class Something:
... def __init__(self):
... self.a = 33
...
>>> with patch('__main__.Something', autospec=True):
... thing = Something()
... thing.a
...
Traceback (most recent call last):
...
AttributeError: Mock object has no attribute 'a'
이 문제를 해결하는 방법에는 몇 가지가 있습니다. 가장 쉬운, 하지만 가장 덜 성가시다고 할 수는 없는, 방법은 단순히 생성 후에 모의 객체에 필요한 어트리뷰트를 설정하는 것입니다. autospec은 사양에 존재하지 않는 어트리뷰트를 꺼내는 것을 허락하지 않기 때문에 그것을 설정하는 것을 막지는 않습니다:
>>> with patch('__main__.Something', autospec=True):
... thing = Something()
... thing.a = 33
...
존재하지 않는 어트리뷰트를 설정하지 못하게 하는 spec과 autospec의 더 적극적인 버전이 있습니다. 이것은 코드가 오직 유효한 어트리뷰트만 설정하도록 보장하려는 경우 유용하지만, 명백히 이 특정 시나리오를 막습니다:
>>> with patch('__main__.Something', autospec=True, spec_set=True):
... thing = Something()
... thing.a = 33
...
Traceback (most recent call last):
...
AttributeError: Mock object has no attribute 'a'
Probably the best way of solving the problem is to add class attributes as
default values for instance members initialised in __init__()
.
Note that if
you are only setting default attributes in __init__()
then providing them via
class attributes (shared between instances of course) is faster too. e.g.
class Something:
a = 33
이것은 또 다른 문제를 일으킵니다. 나중에 다른 형의 객체가 될 멤버에 대해 기본값 None
을 제공하는 것이 일반적입니다. 아무런 어트리뷰트나 메서드에도 액세스할 수 없도록 하므로 None
은 사양으로 쓸모가 없습니다. None
은 결코 스펙으로 유용하지 않고, 일반적으로 다른 형의 멤버를 나타낼 것이기 때문에, autospec은 None
으로 설정된 멤버의 사양을 사용하지 않습니다. 이것들은 평범한 모의 객체일 것입니다 (아마도 - MagicMock):
>>> class Something:
... member = None
...
>>> mock = create_autospec(Something)
>>> mock.member.foo.bar.baz()
<MagicMock name='mock.member.foo.bar.baz()' id='...'>
프로덕션 클래스를 수정하여 기본값을 추가하는 것이 마음에 들지 않으면 더 많은 선택지가 있습니다. 이 중 하나는 단순히 클래스가 아닌 인스턴스를 사양으로 사용하는 것입니다. 다른 하나는 프로덕션 클래스의 서브 클래스를 만들고 프로덕션 클래스에 영향을 주지 않으면서 기본값을 서브 클래스에 추가하는 것입니다. 이 두 가지 모두 사양으로 대체 객체를 사용해야 합니다. 고맙게도 patch()
는 이것을 지원합니다 - 단순히 대체 객체를 autospec 인자로 전달할 수 있습니다:
>>> class Something:
... def __init__(self):
... self.a = 33
...
>>> class SomethingForTest(Something):
... a = 33
...
>>> p = patch('__main__.Something', autospec=SomethingForTest)
>>> mock = p.start()
>>> mock.a
<NonCallableMagicMock name='Something.a' spec='int' id='...'>
이것은 클래스나 이미 인스턴스 화 된 객체에만 적용됩니다. 모킹된 클래스를 호출하여 모의 객체 인스턴스를 만드는 것은 실제 인스턴스를 만들지 않습니다. (dir()
호출과 함께) 어트리뷰트 조회만 수행됩니다.
실링 모의 객체 봉인하기¶
- unittest.mock.seal(mock)¶
Seal은 봉인되는 모의 객체나 이것의 재귀적으로 이미 모의 객체인 어트리뷰트의 어트리뷰트를 액세스할 때 자동 모의 객체 생성을 비활성화합니다.
이름이나 사양을 가진 모의 객체 인스턴스가 어트리뷰트에 대입되면 봉인 체인에서 고려되지 않습니다. 이것은 seal이 모의 객체의 일부를 고정하는 것을 방지할 수 있게 합니다.
>>> mock = Mock() >>> mock.submock.attribute1 = 2 >>> mock.not_submock = mock.Mock(name="sample_name") >>> seal(mock) >>> mock.new_attribute # This will raise AttributeError. >>> mock.submock.attribute2 # This will raise AttributeError. >>> mock.not_submock.attribute2 # This won't raise.
버전 3.7에 추가.
Order of precedence of side_effect
, return_value
and wraps¶
The order of their precedence is:
wraps
If all three are set, mock will return the value from side_effect
,
ignoring return_value
and the wrapped object altogether. If any
two are set, the one with the higher precedence will return the value.
Regardless of the order of which was set first, the order of precedence
remains unchanged.
>>> from unittest.mock import Mock
>>> class Order:
... @staticmethod
... def get_value():
... return "third"
...
>>> order_mock = Mock(spec=Order, wraps=Order)
>>> order_mock.get_value.side_effect = ["first"]
>>> order_mock.get_value.return_value = "second"
>>> order_mock.get_value()
'first'
As None
is the default value of side_effect
, if you reassign
its value back to None
, the order of precedence will be checked between
return_value
and the wrapped object, ignoring
side_effect
.
>>> order_mock.get_value.side_effect = None
>>> order_mock.get_value()
'second'
If the value being returned by side_effect
is DEFAULT
,
it is ignored and the order of precedence moves to the successor to obtain the
value to return.
>>> from unittest.mock import DEFAULT
>>> order_mock.get_value.side_effect = [DEFAULT]
>>> order_mock.get_value()
'second'
When Mock
wraps an object, the default value of
return_value
will be DEFAULT
.
>>> order_mock = Mock(spec=Order, wraps=Order)
>>> order_mock.return_value
sentinel.DEFAULT
>>> order_mock.get_value.return_value
sentinel.DEFAULT
The order of precedence will ignore this value and it will move to the last successor which is the wrapped object.
As the real call is being made to the wrapped object, creating an instance of this mock will return the real instance of the class. The positional arguments, if any, required by the wrapped object must be passed.
>>> order_mock_instance = order_mock()
>>> isinstance(order_mock_instance, Order)
True
>>> order_mock_instance.get_value()
'third'
>>> order_mock.get_value.return_value = DEFAULT
>>> order_mock.get_value()
'third'
>>> order_mock.get_value.return_value = "second"
>>> order_mock.get_value()
'second'
But if you assign None
to it, this will not be ignored as it is an
explicit assignment. So, the order of precedence will not move to the wrapped
object.
>>> order_mock.get_value.return_value = None
>>> order_mock.get_value() is None
True
Even if you set all three at once when initializing the mock, the order of precedence remains the same:
>>> order_mock = Mock(spec=Order, wraps=Order,
... **{"get_value.side_effect": ["first"],
... "get_value.return_value": "second"}
... )
...
>>> order_mock.get_value()
'first'
>>> order_mock.get_value.side_effect = None
>>> order_mock.get_value()
'second'
>>> order_mock.get_value.return_value = DEFAULT
>>> order_mock.get_value()
'third'
If side_effect
is exhausted, the order of precedence will not
cause a value to be obtained from the successors. Instead, StopIteration
exception is raised.
>>> order_mock = Mock(spec=Order, wraps=Order)
>>> order_mock.get_value.side_effect = ["first side effect value",
... "another side effect value"]
>>> order_mock.get_value.return_value = "second"
>>> order_mock.get_value()
'first side effect value'
>>> order_mock.get_value()
'another side effect value'
>>> order_mock.get_value()
Traceback (most recent call last):
...
StopIteration