unittest.mock — 모의 객체 라이브러리

버전 3.3에 추가.

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


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

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

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

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

이전 버전의 파이썬을 위한 unittest.mock의 역 이식이 있습니다, PyPI의 mock에서 제공됩니다.

간략 지침

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

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

    spec이 (문자열 리스트 대신에) 객체이면, __class__는 spec 객체의 클래스를 반환합니다. 이것은 모의 객체가 isinstance() 검사를 통과할 수 있도록 합니다.

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

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

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

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

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

  • return_value: 모의 객체가 호출될 때 반환되는 값. 기본적으로 이것은 새로운 Mock입니다 (처음 액세스할 때 만들어집니다). return_value 어트리뷰트를 참조하십시오.

  • unsafe: 기본적으로 어트리뷰트가 assertassret로 시작하면 AttributeError가 발생합니다. unsafe=True를 전달하면 이러한 어트리뷰트에 액세스 할 수 있습니다.

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

버전 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에서 변경: reset_mock 함수에 두 개의 키워드 전용 인자를 추가했습니다.

같은 객체를 재사용하는 일련의 어서션을 만들려는 경우에 유용할 수 있습니다. reset_mock()은 기본적으로 정규 대입을 사용하여 설정한 반환 값, side_effect 또는 모든 자식 어트리뷰트를 지우지 않음에 유의하십시오. return_valueside_effect를 재설정하려면, 해당 매개 변수를 True로 전달하십시오. 자식 모의 객체와 반환 값 모의 객체(있다면)도 재설정됩니다.

참고

return_valueside_effect는 키워드 전용 인자입니다.

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__

일반적으로 객체의 __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_valueside_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)

클래스에서 프로퍼티나 다른 디스크립터로 사용하기 위한 모의 객체. PropertyMock__get__()__set__() 메서드를 제공하므로 꺼낼 때 반환 값을 지정할 수 있습니다.

객체에서 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_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='...'>

버전 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 같은 어트리뷰트로 기록됩니다.

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_effectNone으로 설정하십시오:

>>> 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_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')]
1

유일한 예외는 매직 메서드와 어트리뷰트(앞뒤에 이중 밑줄을 가진 것)입니다. Mock은 이것을 만들지 않고 대신 AttributeError를 발생시킵니다. 이는 인터프리터가 종종 묵시적으로 이러한 메서드를 요청하고, 매직 메서드를 기대할 때 새 Mock 객체를 얻으면 매우 혼동되기 때문입니다. 매직 메서드 지원이 필요하면 매직 메서드를 참조하십시오.

패처

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

패치는 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_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()는 실제로 딕셔너리가 아닌 딕셔너리류 객체와 함께 사용할 수 있습니다. 최소한 아이템 가져오기, 설정하기, 삭제하기 및 이터레이션이나 멤버십 검사를 지원해야 합니다. 이것은 매직 메서드 __getitem__(), __setitem__(), __delitem__()__iter__()__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

모든 패처에는 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

일반적인 사용 사례는 TestCasesetUp 메서드에서 여러 패치를 수행하는 것입니다:

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

디스크립터와 프락시 객체 패치하기

patchpatch.object 모두 디스크립터를 올바르게 패치하고 복원합니다: 클래스 메서드, 정적 메서드 및 프로퍼티. 이것들을 인스턴스가 아닌 클래스에서 패치해야 합니다. 이들은 또한 장고 settings 객체와 같이 어트리뷰트 액세스를 프락시 하는 일부 객체에서도 작동합니다.

MagicMock과 매직 메서드 지원

매직 메서드 모킹하기

Mock은 “매직 메서드”라고도 하는 파이썬 프로토콜 메서드 모킹을 지원합니다. 이를 통해 모의 객체가 컨테이너나 파이썬 프로토콜을 구현하는 다른 객체를 대체할 수 있습니다.

매직 메서드는 일반 메서드와는 다르게 조회되므로 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__

  • 숫자 메서드 (뒤집히거나 제자리 변형 포함) : __add__, __sub__, __mul__, __matmul__, __div__, __truediv__, __floordiv__, __mod__, __divmod__, __lshift__, __rshift__, __and__, __xor__, __or____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은 대부분의 매직 메서드의 기본 구현이 있는 Mock의 서브 클래스입니다. 매직 메서드를 직접 구성하지 않고도 MagicMock을 사용할 수 있습니다.

생성자 매개 변수는 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

두 동등 비교 메서드 __eq__()__ne__()는 특별합니다. 이들의 반환 값을 변경하여 다른 것을 반환하지 않는 한, side_effect 어트리뷰트를 사용하여 아이덴티티에 대한 기본 동등 비교를 수행합니다:

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

2

매직 메서드는 인스턴스가 아닌 클래스에서 조회되어야 합니다. 다른 버전의 파이썬은 이 규칙을 적용하는 데 일관적이지 않습니다. 지원되는 프로토콜 메서드는 지원되는 모든 버전의 파이썬에서 작동해야 합니다.

3

이 함수는 기본적으로 클래스에 연결되어 있지만, 각 Mock 인스턴스는 다른 것들과 격리되어 있습니다.

도우미

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

FILTER_DIR

unittest.mock.FILTER_DIR

FILTER_DIR은 모의 객체가 dir()에 응답하는 방식을 제어하는 모듈 수준 변수입니다 (파이썬 2.6 이상에서만). 기본값은 True이며, 아래 설명된 필터링을 사용하여 유용한 멤버만 표시합니다. 이 필터링이 마음에 들지 않거나 진단 목적으로 필터를 꺼야 하면, 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__',
 ...

또는 vars(my_mock)(인스턴스 멤버)과 dir(type(my_mock))(형 멤버)을 사용하여 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에서 변경: 이터레이션(가령 for 루프)에서 read_data를 올바르게 소비하도록 구현에 __iter__()를 추가했습니다.

open()을 컨텍스트 관리자로 사용하는 것은 파일 핸들이 올바르게 닫히도록 보장하는 좋은 방법이고 점차 일반화되고 있습니다:

with open('/some/path', 'w') as f:
    f.write('something')

문제는 open()에 대한 호출을 모킹하더라도 컨텍스트 관리자로 사용되는 것은 반환된 객체라는 것입니다 (그리고 __enter__()__exit__()가 호출됩니다).

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

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.

더 심각한 문제는 인스턴스 어트리뷰트가 __init__() 메서드에서 만들어지고 클래스에 전혀 존재하지 않는 것이 일반적이라는 것입니다. autospec은 동적으로 만들어진 어트리뷰트를 알 수 없으며 api를 가시적 어트리뷰트로 제한합니다.

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

아마도 문제를 해결하는 가장 좋은 방법은 __init__()에서 초기화되는 인스턴스 멤버의 기본값으로 클래스 어트리뷰트를 추가하는 것입니다. __init__()에서 기본 어트리뷰트만 설정하고 있다면 클래스 어트리뷰트(물론 인스턴스 간에 공유됩니다)를 통해 제공하는 것이 더 빠르기도 합니다. 예를 들어

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

이것은 클래스나 이미 인스턴스 화 된 객체에만 적용됩니다. 모킹된 클래스를 호출하여 모의 객체 인스턴스를 만드는 것은 실제 인스턴스를 만들지 않습니다. (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에 추가.