mock으로 readonly 속성을 어떻게 조롱 합니까?
나는 시도했다 :
setattr(obj.__class__, 'property_to_be_mocked', mock.Mock())
그러나 문제는 그것이 클래스의 모든 인스턴스에 적용된다는 것입니다.
다른 생각이 있습니까? 나는 전체 객체를 조롱하는 것이 아니라이 특정 속성 만 모의하고 싶습니다.
답변
더 나은 방법은 메서드를 직접 PropertyMock
조롱하는 것보다 속성을로 조롱하는 __get__
것입니다.
문서에 명시되어 있습니다 . 검색 unittest.mock.PropertyMock
: 클래스에서 속성 또는 기타 설명 자로 사용하기위한 모의. 가져올 때 반환 값을 지정할 수 있도록 및 메서드를 PropertyMock
제공합니다 .__get__
__set__
방법은 다음과 같습니다.
class MyClass:
@property
def last_transaction(self):
# an expensive and complicated DB query here
pass
def test(unittest.TestCase):
with mock.patch('MyClass.last_transaction', new_callable=PropertyMock) as mock_last_transaction:
mock_last_transaction.return_value = Transaction()
myclass = MyClass()
print myclass.last_transaction
mock_last_transaction.assert_called_once_with()
답변
사실, 대답은 (평소처럼) 문서 에 있었는데, 예제를 따랐을 때 클래스 대신 인스턴스에 패치를 적용하고 있었기 때문입니다.
방법은 다음과 같습니다.
class MyClass:
@property
def last_transaction(self):
# an expensive and complicated DB query here
pass
테스트 스위트에서 :
def test():
# Make sure you patch on MyClass, not on a MyClass instance, otherwise
# you'll get an AttributeError, because mock is using settattr and
# last_transaction is a readonly property so there's no setter.
with mock.patch(MyClass, 'last_transaction') as mock_last_transaction:
mock_last_transaction.__get__ = mock.Mock(return_value=Transaction())
myclass = MyClass()
print myclass.last_transaction
답변
재정의하려는 속성이있는 개체가 모의 개체 인 경우을 사용할 필요가 없습니다 patch
.
대신 모의 유형 에 대한 PropertyMock
속성을 만든 다음 재정의 할 수 있습니다 . 예를 들어 속성을 재정 의하여 반환하려면 다음을 수행하십시오.mock_rows.pages
(mock_page, mock_page,)
mock_page = mock.create_autospec(reader.ReadRowsPage)
# TODO: set up mock_page.
mock_pages = mock.PropertyMock(return_value=(mock_page, mock_page,))
type(mock_rows).pages = mock_pages
답변
아마도 스타일의 문제이지만 테스트에서 데코레이터를 선호하는 경우 @jamescastlefield의 답변 을 다음과 같이 변경할 수 있습니다.
class MyClass:
@property
def last_transaction(self):
# an expensive and complicated DB query here
pass
class Test(unittest.TestCase):
@mock.patch('MyClass.last_transaction', new_callable=PropertyMock)
def test(self, mock_last_transaction):
mock_last_transaction.return_value = Transaction()
myclass = MyClass()
print myclass.last_transaction
mock_last_transaction.assert_called_once_with()
답변
pytest
와 함께 사용하는 경우 pytest-mock
코드를 단순화하고 컨텍스트 관리자 (예 with
: 다음과 같은 문)를 사용하지 않아도 됩니다.
def test_name(mocker): # mocker is a fixture included in pytest-mock
mocked_property = mocker.patch(
'MyClass.property_to_be_mocked',
new_callable=mocker.PropertyMock,
return_value='any desired value'
)
o = MyClass()
print(o.property_to_be_mocked) # this will print: any desired value
mocked_property.assert_called_once_with()
답변
mocked 속성에 액세스했는지 여부를 테스트하고 싶지 않다면 간단히 예상되는 return_value
.
with mock.patch(MyClass, 'last_transaction', Transaction()):
...
답변
@property
원본에 의존 하기 위해 모의 가 필요한 경우 __get__
사용자 정의를 만들 수 있습니다.MockProperty
class PropertyMock(mock.Mock):
def __get__(self, obj, obj_type=None):
return self(obj, obj_type)
용법:
class A:
@property
def f(self):
return 123
original_get = A.f.__get__
def new_get(self, obj_type=None):
return f'mocked result: {original_get(self, obj_type)}'
with mock.patch('__main__.A.f', new_callable=PropertyMock) as mock_foo:
mock_foo.side_effect = new_get
print(A().f) # mocked result: 123
print(mock_foo.call_count) # 1