(pytest) 为什么 属性 mock 在 fixture 中不起作用?
(pytest) Why doesn't property mock work in fixture?
我有一个 class 具有一些属性。在我的测试中,我需要设置一个夹具,并模拟属性。但是,patch 仅在 fixture 函数中起作用,在调用 fixture 时不起作用。知道如何解决这个问题吗?
这是问题的简化版本。假设这是我的 class 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
中的第二个打印函数打印 this name should not matter
,这意味着 propertyMock 在这里不起作用。知道为什么会发生这种情况以及如何解决这个问题吗?
如果你想在 pytest
中进行猴子修补,你可以使用他们的 built-in fixture monkeypatch
,它可以插入到所有带有 scope = function
的 fixture 中。这是我的代码库中的示例:
@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
放错地方了;它需要应用到补丁 returns 的 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"
我有一个 class 具有一些属性。在我的测试中,我需要设置一个夹具,并模拟属性。但是,patch 仅在 fixture 函数中起作用,在调用 fixture 时不起作用。知道如何解决这个问题吗?
这是问题的简化版本。假设这是我的 class 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
中的第二个打印函数打印 this name should not matter
,这意味着 propertyMock 在这里不起作用。知道为什么会发生这种情况以及如何解决这个问题吗?
如果你想在 pytest
中进行猴子修补,你可以使用他们的 built-in fixture monkeypatch
,它可以插入到所有带有 scope = function
的 fixture 中。这是我的代码库中的示例:
@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
放错地方了;它需要应用到补丁 returns 的 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"