Как смоделировать атрибут экземпляра, инициируемый функцией - PullRequest
0 голосов
/ 27 марта 2020

Я пишу некоторые модульные тесты для класса, у которого установлены атрибуты экземпляра в функции, которая не является конструктором. Класс выглядит следующим образом:

class MyClass:
    def __init__(self):
        self.__A = False
        self.__B = False

    def set_C(self):
        self.__C = True

    def my_func(self):
        self.set_C()

        if self.__A:
            self.print_val(self.__A)
        if self.__B:
            self.print_val(self.__B)
        if self.__C:
            self.print_val(self.__C)

    def print_val(self, val):
        print(val)

Я пытаюсь написать тест для my_func(), чтобы проверить, что print_val() выполняется, если атрибут оценивается как true. Пока что у меня есть тест (игнорирующий импорт)

class TestMyClass:

    @patch("MyClass.print_val")
    def test_my_func(self, mock_print_val):
        my_class = MyClass()
        # setattr(my_class, "C", False)
        with patch.object(my_class, "C", True) as mock_C:
            my_class.my_func()
            mock_print_val.assert_called()

. Позже я буду редактировать вызов assert, чтобы проверить, был ли он вызван с указанными c параметрами, но основная идея c чтобы проверить, что print_val () работает.

Я заметил, что без setattr(my_class, "C", False) выдаст мне следующую ошибку AttributeError: <...> does not have attribute 'C'.

При setattr() при отладке я смогу увидеть атрибут C в Защищенные атрибуты в окне переменных непосредственно перед его печатью, но он все равно выдает ошибку (На самом деле я не уверен, является ли setattr() правильным путем к go, просто я пробовал что-то, так как он сказал, что атрибут не существует)

Я также знаю, что если я изменю код к следующему, чтобы пропатчить атрибут из __init__, он работает просто отлично

class TestMyClass:

    @patch("MyClass.print_val")
    def test_my_func(self, mock_print_val):
        my_class = MyClass()
        with patch.object(my_class, "A", True) as mock_C:
            my_class.my_func()
            mock_print_val.assert_called()

Из проведенного мною исследования я видел похожие проблемы, но они были для атрибутов класса или немного отличались. Я прошу прощения, если этот вопрос был задан ранее, и я пропустил его.

Редактировать: При попытке выяснить решение, я заметил, что я мог бы просто сделать

class TestMyClass:

    @patch("MyClass.print_val")
    def test_my_func(self, mock_print_val):
        my_class = MyClass()
        my_class.C = True
        my_class.my_func()
        mock_print_val.assert_called()

Если атрибут C был опубликован c и печать это как print_val(self.C) не вызовет никаких проблем. Я отредактировал исходный вопрос, чтобы уточнить, что атрибут должен быть защищен, а не опубликован c.

1 Ответ

0 голосов
/ 27 марта 2020

Работая над другими тестами, мне удалось найти решение ..

То, что у меня есть:

class TestMyClass:

    @patch("MyClass.print_val")
    def test_my_func(self, mock_print_val):
        my_class = MyClass()
        my_class._MyClass__C = True
        my_class.my_func()
        mock_print_val.assert_called()

Это, похоже, сработало. Если атрибут в MyClass имеет префикс с одним подчеркиванием или вообще не имеет префикса *, можно использовать my_class._C или my_class._c, но, поскольку он имеет префикс с двумя подчеркиваниями, я должен был сделать my_class._MyClass__C.

Я не знаю, является ли это безопасным и рекомендуемым решением, хотя ..

...