(pytest) Почему макет свойства не работает в приспособлении?

У меня есть класс с некоторыми свойствами. В моем тесте мне нужно настроить прибор и смоделировать свойства. Однако патч работает только в функции прибора, а не при вызове прибора. Есть идеи, как это исправить?

Вот упрощенная версия задачи. Предположим, что это мой класс 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 здесь не работает. Любая идея, почему это происходит и как это исправить?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
1 670
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Если вы хотите залатать что-то в 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"

Другие вопросы по теме