«Если рабочий хочет хорошо выполнять свою работу, он должен сначала заточить свои инструменты» — Конфуций, «Аналитики Конфуция. Лу Лингун»
титульная страница > программирование > Издевательские классы Python

Издевательские классы Python

Опубликовано 3 ноября 2024 г.
Просматривать:296

Mocking Python Classes

Недавно мне пришлось писать модульные тесты с использованием 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. Он используется при тестировании для временной замены атрибута данного объекта макетом или другим значением.

Аргументы

  1. target=ClassA: объект (обычно класс), атрибут которого мы хотим исправить.
  2. атрибут="__init__": имя атрибута, который мы хотим исправить.
  3. return_value=None: замена метода __init__ функцией, которая ничего не делает

Таким образом, мы можем создавать фиктивные переменные в нашем приспособлении.
Подробнее о 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

Надеюсь, это поможет! :)

Заявление о выпуске Эта статья воспроизведена по адресу: https://dev.to/chen_ashkenazi/mocking-python-classes-4h96?1. Если есть какие-либо нарушения, свяжитесь с [email protected], чтобы удалить их.
Последний учебник Более>

Изучайте китайский

Отказ от ответственности: Все предоставленные ресурсы частично взяты из Интернета. В случае нарушения ваших авторских прав или других прав и интересов, пожалуйста, объясните подробные причины и предоставьте доказательства авторских прав или прав и интересов, а затем отправьте их по электронной почте: [email protected]. Мы сделаем это за вас как можно скорее.

Copyright© 2022 湘ICP备2022001581号-3