unittest.mock — mock object library

Added in version 3.3.

소스 코드: Lib/unittest/mock.py


unittest.mock은 파이썬에서 테스트하기 위한 라이브러리입니다. 테스트 대상 시스템의 일부를 모의 객체로 교체하고 그들이 사용된 방식에 대해 어서션(assertion)을 할 수 있습니다.

unittest.mock은 핵심 Mock 클래스를 제공하여 테스트 스위트 전체에 걸쳐 많은 스텁을 만들 필요가 없도록 합니다. 작업을 수행한 후, 사용된 메서드 / 어트리뷰트와 호출에 제공된 인자에 대한 어서션을 할 수 있습니다. 일반적인 방법으로 반환 값을 지정하고 필요한 어트리뷰트를 설정할 수도 있습니다.

또한, mock은 테스트 스코프 내에서 모듈과 클래스 수준 어트리뷰트의 패치를 처리하는 patch() 데코레이터를 고유한 객체 생성을 위한 sentinel과 함께 제공합니다. Mock, MagicMockpatch() 사용 방법에 대한 몇 가지 예는 간략 지침을 참조하십시오.

Mock은 unittest와 함께 사용하도록 설계되었고 많은 모킹(mocking) 프레임워크에서 사용하는 ‘기록(record) -> 재생(replay)’ 대신 ‘액션(action) -> 어서션(assertion)’ 패턴을 기반으로 합니다.

There is a backport of unittest.mock for earlier versions of Python, available as mock on PyPI.

간략 지침

MockMagicMock 객체는 그것들을 액세스함에 따라 모든 어트리뷰트와 메서드를 작성하고 사용 방식에 대한 세부 사항을 저장합니다. 반환 값을 지정하거나 사용 가능한 어트리뷰트를 제한하도록 구성한 다음, 사용된 방식에 대한 어서션을 만들 수 있습니다:

>>> 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 allows you to perform side effects, including raising an exception when a mock is called:

>>> from unittest.mock import Mock
>>> 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]. 같은 어트리뷰트에 액세스하면 항상 같은 모의 객체를 반환합니다. 모의 객체는 사용 방법을 기록하여, 코드가 모의 객체에 대해 수행한 작업에 대한 어서션을 만들 수 있도록 합니다.

MagicMockMock의 서브 클래스이며, 모든 매직 메서드가 미리 만들어져 사용할 준비가 되어있습니다. 콜러블이 아닌 변형도 있어서, 콜러블이 아닌 객체를 모킹할 때 유용합니다: NonCallableMockNonCallableMagicMock

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가 발생합니다.

    If spec is an object (rather than a list of strings) then __class__ returns the class of the spec object. This allows mocks to pass isinstance() tests.

  • spec_set: spec의 더 엄격한 변형. 사용되면, spec_set으로 전달된 객체에 없는 모의 객체의 어트리뷰트를 설정하거나 얻으려고 시도하면 AttributeError가 발생합니다.

  • side_effect: Mock이 호출될 때마다 호출되는 함수. side_effect 어트리뷰트를 참조하십시오. 예외를 발생시키거나 반환 값을 동적으로 변경하는 데 유용합니다. 함수는 모의 객체와 같은 인자로 호출되며, DEFAULT를 반환하지 않는 한, 이 함수의 반환 값이 반환 값으로 사용됩니다.

    또는 side_effect는 예외 클래스나 인스턴스일 수 있습니다. 이 경우 모의 객체가 호출될 때 그 예외가 발생합니다.

    side_effect가 이터러블이면 모의 객체에 대한 각 호출은 이터러블의 다음 값을 반환합니다.

    side_effectNone으로 설정하여 지울 수 있습니다.

  • 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. Passing unsafe=True will allow access to these attributes.

    Added in version 3.5.

  • wraps: 모의 객체가 감쌀 항목. wrapsNone이 아니면 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()

Added in version 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.

Added in version 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.

Added in version 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

This can be useful where you want to make a series of assertions that reuse the same object.

return_value parameter when set to True resets return_value:

>>> mock = Mock(return_value=5)
>>> mock('hello')
5
>>> mock.reset_mock(return_value=True)
>>> mock('hello')  
<Mock name='mock()' id='...'>

side_effect parameter when set to True resets side_effect:

>>> mock = Mock(side_effect=ValueError)
>>> mock('hello')
Traceback (most recent call last):
  ...
ValueError
>>> mock.reset_mock(side_effect=True)
>>> mock('hello')  
<Mock name='mock()' id='...'>

Note that reset_mock() doesn’t clear the return_value, side_effect or any child attributes you have set using normal assignment by default.

Child mocks are reset as well.

버전 3.6에서 변경: Added two keyword-only arguments to the reset_mock function.

mock_add_spec(spec, spec_set=False)

모의 객체에 사양을 추가합니다. spec은 객체이거나 문자열 리스트일 수 있습니다. spec의 어트리뷰트 만 모의 객체에서 어트리뷰트로 꺼낼 수 있습니다.

spec_set이 참이면 스펙에 있는 어트리뷰트 만 설정할 수 있습니다.

attach_mock(mock, attribute)

이름과 부모를 치환해서, 이것의 어트리뷰트(attribute)로 모의 객체(mock)를 연결합니다. 연결된 모의 객체에 대한 호출은 이것의 method_callsmock_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_effectNone으로 설정하면 지워집니다:

>>> 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_callsmock_calls 리스트의 멤버와 함께 call_argscall 객체입니다. 이들은 튜플이므로, 개별 인자를 얻고 더 복잡한 어서션을 하기 위해 언팩할 수 있습니다. call 튜플을 참조하십시오.

버전 3.8에서 변경: argskwargs 프로퍼티를 추가했습니다.

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__

Normally the __class__ attribute of an object will return its type. For a mock object with a spec, __class__ returns the spec class instead. This allows mock objects to pass isinstance() tests for the object they are replacing / masquerading as:

>>> mock = Mock(spec=3)
>>> isinstance(mock, int)
True

__class__ is assignable to, this allows a mock to pass an isinstance() check without forcing you to use a spec:

>>> 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_valueside_effect는 예외입니다.

Mock objects that use a class or an instance as a spec or spec_set are able to pass isinstance() tests:

>>> 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()

조심

If an AttributeError is raised by PropertyMock, it will be interpreted as a missing descriptor and __getattr__() will be called on the parent mock:

>>> m = MagicMock()
>>> no_attribute = PropertyMock(side_effect=AttributeError)
>>> type(m).my_property = no_attribute
>>> m.my_property
<MagicMock name='mock.my_property' id='140165240345424'>

See __getattr__() for details.

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_effectreturn_value를 제공하는 비동기 함수입니다:

  • side_effect가 함수이면, 비동기 함수는 해당 함수의 결과를 반환합니다,

  • side_effect가 예외이면, 비동기 함수는 예외를 발생시킵니다,

  • side_effect가 이터러블이면, 비동기 함수는 이터러블의 다음 값을 반환하지만, 결과 시퀀스가 소진되면 StopAsyncIteration이 즉시 발생합니다,

  • side_effect가 정의되지 않으면, 비동기 함수는 return_value에 의해 정의된 값을 반환하므로, 기본적으로 비동기 함수는 새 AsyncMock 객체를 반환합니다.

Mock이나 MagicMockspec을 비동기 함수로 설정하면 호출 후에 코루틴 객체가 반환됩니다.

>>> async def async_func(): pass
...
>>> mock = MagicMock(async_func)
>>> mock
<MagicMock spec='function' id='...'>
>>> mock()  
<coroutine object AsyncMockMixin._mock_call at ...>

Mock, MagicMock 또는 AsyncMockspec을 비동기와 동기 함수가 있는 클래스로 설정하면 동기 함수를 자동으로 감지하고 그들을 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='...'>

Added in version 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_argscall_args_list 같은 어트리뷰트로 기록됩니다.

If side_effect is set then it will be called after the call has been recorded, so if side_effect raises an exception the call is still recorded.

호출될 때 모의 객체가 예외를 발생시키는 가장 간단한 방법은 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')]

If side_effect is a function then whatever that function returns is what calls to the mock return. The side_effect function is called with the same arguments as the mock. This allows you to vary the return value of the call dynamically, based on the input:

>>> 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)]

If you want the mock to still return the default return value (a new mock), or any set return value, then there are two ways of doing this. Either return return_value from inside side_effect, or return 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

To remove a side_effect, and return to the default behaviour, set the side_effect to 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

The side_effect can also be any iterable object. Repeated calls to the mock will return values from the iterable (until the iterable is exhausted and a StopIteration is raised):

>>> 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

어트리뷰트 삭제

모의 객체는 요청 시 어트리뷰트를 만듭니다. 이를 통해 모든 형의 객체인 것처럼 가장할 수 있습니다.

You may want a mock object to return False to a hasattr() call, or raise an AttributeError when an attribute is fetched. You can do this by providing an object as a spec for a mock, but that isn’t always convenient.

어트리뷰트를 삭제하여 어트리뷰트를 “차단”합니다. 일단 삭제되면, 어트리뷰트에 액세스할 때 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_callsmock_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 문 내부에서, targetnew 객체로 패치됩니다. 함수/with 문이 종료될 때 패치가 복구됩니다.

new가 생략되면, 대상(target)은 패치된 객체가 비동기 함수이면 AsyncMock으로, 그렇지 않으면 MagicMock으로 치환됩니다. patch()가 데코레이터로 사용되고 new가 생략되면, 만들어진 모의 객체는 데코레이트 되는 함수에 대한 추가 인자로 전달됩니다. patch()가 컨텍스트 관리자로 사용되면 만들어진 모의 객체는 컨텍스트 관리자에 의해 반환됩니다.

target'package.module.ClassName' 형식의 문자열이어야 합니다. target이 임포트되고 지정된 객체를 new 객체로 치환하므로, patch()를 호출하는 환경에서 target을 임포트 할 수 있어야 합니다. 데코레이트 하는 시간이 아니라 데코레이트 된 함수가 실행될 때 대상(target)을 임포트 합니다.

patch가 여러분을 위해 만든다면 specspec_set 키워드 인자는 MagicMock으로 전달됩니다.

또한 spec=Truespec_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를 전달할 필요가 없습니다, 기본적으로 추가됩니다.

Patch can be used as a TestCase class decorator. It works by decorating each test method in the class. This reduces the boilerplate code when your test methods share a common patchings set. patch() finds tests by looking for method names that start with patch.TEST_PREFIX. By default this is 'test', which matches the way unittest finds tests. You can specify an alternative prefix by setting 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를 원하는 것으로 설정할 수 있습니다.

To configure return values on methods of instances on the patched class you must do this on the return_value. For example:

>>> 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_valueside_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()

버전 3.8에서 변경: patch()는 이제 target이 비동기 함수면 AsyncMock을 반환합니다.

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, autospecnew_callablepatch()와 같은 의미입니다. 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, createpatch.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, autospecnew_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

All the patchers have start() and stop() methods. These make it simpler to do patching in setUp methods or where you want to do multiple patches without nesting decorators or with statements.

To use them call patch(), patch.object() or patch.dict() as normal and keep a reference to the returned patcher object. You can then call start() to put the patch in place and stop() to undo it.

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

A typical use case for this might be for doing multiple patches in the setUp method of a TestCase:

>>> 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_functiona.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 변형이 있습니다: MagicMockNonCallableMagicMock.

class unittest.mock.MagicMock(*args, **kw)

MagicMock is a subclass of Mock with default implementations of most of the magic methods. You can use MagicMock without having to configure the magic methods yourself.

생성자 매개 변수는 Mock과 같은 의미입니다.

spec이나 spec_set 인자를 사용하면 오직 사양에 존재하는 매직 메서드만 만들어집니다.

class unittest.mock.NonCallableMagicMock(*args, **kw)

콜러블이 아닌 MagicMock 버전.

생성자 매개 변수는 콜러블이 아닌 모의 객체에 의미가 없는 return_valueside_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__

도우미

sentinel

unittest.mock.sentinel

sentinel 객체는 테스트에 고유한(unique) 객체를 제공하는 편리한 방법을 제공합니다.

어트리뷰트는 이름으로 어트리뷰트에 액세스할 때 요청에 따라 만들어집니다. 같은 어트리뷰트에 액세스하면 항상 같은 객체가 반환됩니다. 반환된 객체는 테스트 실패 메시지를 읽을 수 있도록 적절한 repr을 갖습니다.

버전 3.7에서 변경: sentinel 어트리뷰트는 이제 복사되거나 피클될 때 아이덴티티를 유지합니다.

때로 테스트할 때 특정 객체가 다른 메서드에 대한 인자로 전달되거나 반환되는지 테스트해야 할 때가 있습니다. 이것을 테스트하기 위해 이름 붙은 sentinel 객체를 만드는 것이 일반적일 수 있습니다. sentinel은 이와 같은 객체의 아이덴티티를 만들고 테스트하는 편리한 방법을 제공합니다.

이 예에서는 methodsentinel.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_callsmethod_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_listMock.mock_calls 어트리뷰트에 있는 call 객체는 포함된 개별 인자를 얻기 위해 검사될 수 있습니다.

Mock.call_argsMock.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_setTrue이면 사양 객체에 존재하지 않는 어트리뷰트를 설정하려는 시도는 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)

ANYmock_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 FILTER_DIR.

mock_open

unittest.mock.mock_open(mock=None, read_data=None)

open()의 사용을 대체하기 위한 모의 객체를 만드는 도우미 함수. 직접 호출되거나 컨텍스트 관리자로 사용되는 open()에 대해 작동합니다.

mock 인자는 구성할 모의 객체입니다. None(기본값)이면 표준 파일 핸들에서 사용 가능한 메서드나 어트리뷰트로 API가 제한된 MagicMock이 만들어집니다.

read_data is a string for the read(), readline(), and readlines() methods of the file handle to return. Calls to those methods will take data from read_data until it is depleted. The mock of these methods is pretty simplistic: every time the mock is called, the read_data is rewound to the start. If you need more control over the data that you are feeding to the tested code you will need to customize this mock for yourself. When that is insufficient, one of the in-memory filesystem packages on PyPI can offer a realistic filesystem for testing.

버전 3.4에서 변경: Added readline() and readlines() support. The mock of read() changed to consume read_data rather than returning it on each call.

버전 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'

자동 사양

Autospeccing is based on the existing spec feature of mock. It limits the api of mocks to the api of an original object (the spec), but it is recursive (implemented lazily) so that attributes of mocks only have the same api as the attributes of the spec. In addition mocked functions / methods have the same call signature as the original so they raise a TypeError if they are called incorrectly.

자동 사양이 작동하는 방식을 설명하기 전에, 이것이 필요한 이유는 이렇습니다.

Mock is a very powerful and flexible object, but it suffers from a flaw which is general to mocking. If you refactor some of your code, rename members and so on, any tests for code that is still using the old api but uses mocks instead of the real objects will still pass. This means your tests can all pass even though your code is broken.

버전 3.5에서 변경: Before 3.5, tests with a typo in the word assert would silently pass when they should raise an error. You can still achieve this behavior by passing unsafe=True to Mock.

이것이 단위 테스트뿐만 아니라 통합 테스트가 필요한 또 다른 이유입니다. 모든 것을 분리해서 테스트하는 것은 괜찮고 멋지지만, 단위들이 어떻게 “서로 연결되어” 있는지 테스트하지 않으면 테스트가 발견할 수도 있을 버그에 대한 여지가 여전히 많습니다.

unittest.mock already provides a feature to help with this, called speccing. If you use a class or instance as the spec for a mock then you can only access attributes on the mock that exist on the real class:

>>> 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=Truepatch() / 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='...'>

You can see that request.Request has a spec. request.Request takes two arguments in the constructor (one of which is self). Here’s what happens if we try to call it incorrectly:

>>> 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 objects are not callable, so the return value of instantiating our mocked out request.Request is a non-callable mock. With the spec in place any typos in our asserts will raise the correct error:

>>> 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
...

존재하지 않는 어트리뷰트를 설정하지 못하게 하는 specautospec의 더 적극적인 버전이 있습니다. 이것은 코드가 오직 유효한 어트리뷰트만 설정하도록 보장하려는 경우 유용하지만, 명백히 이 특정 시나리오를 막습니다:

>>> 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='...'>

실링 모의 객체 봉인하기

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.

Added in version 3.7.

Order of precedence of side_effect, return_value and wraps

The order of their precedence is:

  1. side_effect

  2. return_value

  3. 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