(pytest)为什么属性模拟在灯具中不起作用?

时间:2019-05-28 14:20:12

标签: python pytest fixtures

我有一个带有某些属性的类。在测试中,我需要设置一个夹具,并模拟其属性。但是,补丁仅在fixture功能中起作用,而在调用fixture时不起作用。知道如何解决这个问题吗?

这是问题的简化版本。假设这是我的课程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在这里不起作用。知道为什么会这样以及如何解决吗?

2 个答案:

答案 0 :(得分:1)

如果要在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

答案 1 :(得分:0)

您有三个问题。首先,您要修补灯具功能,但您应该修补测试功能。这是因为您编写方法的断言不在修补程序的范围之内。

第二,您应该抛弃多余的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"