Недавно мне пришлось писать модульные тесты с использованием Pytest для модуля Python. Модуль содержит класс, в конструкторе которого инициализируются другие классы.
Как обычно, я создал приспособление для этого класса, чтобы упростить написание теста для каждого метода класса. На этом этапе я столкнулся с некоторыми проблемами, когда пытался имитировать различные классы, инициированные в конструкторе. Издевательство не сработало, и экземпляры этих классов все еще создавались.
После некоторых исследований и объединения нескольких различных решений, которые я нашел в Интернете, я хочу поделиться тем, как мне удалось имитировать классы.
Вот пример класса, который я пытался высмеять:
class ClassA: def __init__(self): self.class_b = ClassB() self.class_c = ClassC() self.count = 0
Мы хотим установить значение для каждого поля этого класса во время тестов. Это значение может быть None или макетом класса, но нам не нужны инициализации классов ClassB и ClassC.
В нашем случае давайте решим, что self.class_b и self.class_c должны быть макетами:
@pytest.fixture def mock_class_b(): class_b = Mock(spec=ClassB) return class_b @pytest.fixture def mock_class_c(): class_c = Mock(spec=ClassC) return class_c
Итак, приспособление для этого класса, которое служит нашей цели, выглядит следующим образом:
@pytest.fixture def class_a_mock(mock_class_b, mock_class_c): with patch.object(target=ClassA, attribute="__init__", return_value=None) as mock_init: class_a = ClassA() class_a.class_b = mock_class_b class_a.class_c = mock_class_c class_b.count = 0 return class_a
Важная часть — как использовать функцию patch.object, которая находится в модуле unittest.mock в Python. Он используется при тестировании для временной замены атрибута данного объекта макетом или другим значением.
Аргументы
Таким образом, мы можем создавать фиктивные переменные в нашем приспособлении.
Подробнее о patch.object
Я написал это руководство для такого рода случаев, когда по какой-либо причине мы не можем изменить код класса A. Однако я обычно рекомендую модифицировать код, если это возможно, не для того, чтобы изменить логику, а для того, чтобы сделать его более тестируемым. .
Вот несколько примеров того, как изменить класс A, чтобы сделать его более тестируемым:
Вариант 1: Передайте экземпляры классов B и C в качестве параметров.
Таким образом, когда мы пишем фикстуру, мы можем передавать макеты вместо экземпляров.
class ClassA: def __init__(self, class_b_instance, class_c_instance): self.class_b = class_b_instance self.class_c = class_c_instance self.count = 0
Вариант 2: Создайте логическую переменную, указывающую тестовый режим.
Таким образом, мы можем решить, какие поля класса A получат или не получат значение при его инициализации.
class ClassA: def __init__(self, test_mode=False): if not test_mode: self.class_b = ClassB() self.class_c = ClassC() self.count = 0
Вариант 3: Выполните инициализацию класса в отдельном методе.
Этот подход дает нам возможность избежать вызова set_class_variables в тестовом модуле.
class ClassA: def __init__(self): self.class_b = None self.class_c = None self.count = None def set_class_variables(self): self.class_b = ClassB() self.class_c = ClassC() self.count = 0
Надеюсь, это поможет! :)
Отказ от ответственности: Все предоставленные ресурсы частично взяты из Интернета. В случае нарушения ваших авторских прав или других прав и интересов, пожалуйста, объясните подробные причины и предоставьте доказательства авторских прав или прав и интересов, а затем отправьте их по электронной почте: [email protected]. Мы сделаем это за вас как можно скорее.
Copyright© 2022 湘ICP备2022001581号-3