У меня есть класс с некоторыми свойствами. В моем тесте мне нужно настроить прибор и смоделировать свойства. Однако патч работает только в функции прибора, а не при вызове прибора. Есть идеи, как это исправить?
Вот упрощенная версия задачи. Предположим, что это мой класс Panda
:
class Panda(object):
def __init__(self, name):
self.panda_name = name
@property
def name(self):
return self.panda_name
и это мой тест
import pytest
from unittest.mock import patch, PropertyMock
from tmp import Panda
@pytest.fixture
@patch(
'tmp.Panda.name',
new_callable=PropertyMock,
return_value = "yuanyuan")
def fixture_panda(mk_name):
p = Panda("this name should not matter")
print(p.name) # print "yuanyuan"
return p
def test_panda_fixture(fixture_panda):
p = fixture_panda
print(p.name) # print "this name should not matter"
# this test fails
assert p.name == "yuanyuan"
Первая функция печати в fixture_panda
напечатает yuanyuan
, что означает, что propertyMock работает так, как ожидалось. Однако вторая функция печати в test_panda_fixture
print this name should not matter
, что означает, что свойствоMock здесь не работает. Любая идея, почему это происходит и как это исправить?
Если вы хотите залатать что-то в pytest
, вы можете использовать их встроенный фикстур monkeypatch
, который можно вставить во все фикстуры с scope = function
. Вот пример из моей кодовой базы:
@pytest.fixture(scope = "function", autouse=True)
def no_jwt(monkeypatch):
"""Monkeypatch the JWT verification functions for tests"""
monkeypatch.setattr("flask_jwt_extended.verify_jwt_in_request", lambda: print("Verify"))
Если я применю это к вашему примеру, я думаю, что что-то вроде этого должно работать:
@pytest.fixture
def fixture_panda(monkeypatch, mk_name):
monkeypatch.setattr('tmp.Panda.name', "yuanyuan")
p = Panda("this name should not matter")
print(p.name) # print "yuanyuan"
return p
У тебя три проблемы. Во-первых, вы исправляете функцию фиксации, но вы должны исправлять тестовую функцию. Это потому, что то, как вы это написали, утверждение выходит за рамки исправления.
Во-вторых, вы должны избавиться от лишнего mkname
.
В-третьих, ваш return_value
не на своем месте; он должен применяться к объекту PropertyMock
, который возвращает патч, а не в качестве параметра функции исправления. При использовании new_callable
вам необходимо установить его в настройках теста, например:
@patch('tmp.Panda.name', new_callable=PropertyMock)
def test_panda_fixture(mock_name, fixture_panda):
mock_name.return_value = "yuanyuan"
...
Однако вы можете сделать это в декораторе, используя new
вместо new_callable
. Вот рабочая версия, которая показывает этот подход:
import pytest
from unittest.mock import patch, PropertyMock
from tmp import Panda
@pytest.fixture
def fixture_panda():
p = Panda("this name should not matter")
print(p.name) # print "yuanyuan"
return p
@patch('tmp.Panda.name', new=PropertyMock(return_value = "yuanyuan"))
def test_panda_fixture(fixture_panda):
p = fixture_panda
print(p.name) # print "this name should not matter"
# this test fails
assert p.name == "yuanyuan"