Как правильно тестировать деструкторы в Python? - PullRequest
1 голос
/ 11 апреля 2019

Я хочу проверить, что деструктор объекта Python вызывается и работает правильно, то есть он не вызывает ошибок и не возвращает неверный код выхода.

Я застрял в написании модульного теста,потому что кажется, что модульное тестирование заканчивается до удаления объекта.Мне не удалось принудительно удалить объект до завершения теста, и я не могу позволить себе вызывать __del__ непосредственно в моих тестах по двум причинам:

  • Это не совсем такто, что я тестирую

  • Это фактически приводит к тому, что объект уничтожается дважды, и в моем случае деструктор освобождает часть памяти, поэтому при вызове дважды он создает ошибку сегментации.

Чтобы проиллюстрировать это, я создал игрушечный пример, где у меня есть два объекта.Первый, MyWrongObject, содержит ошибку в деструкторе, а второй MyCorrectObject является правильным.Я написал тесты для каждого из этих объектов.Один из них должен быть успешным, а другой - неудачным.

import unittest
import gc


class MyWrongObject(object):
    def __init__(self):
        self.del_calls = 0

    def __del__(self):
        if self.del_calls:
            # Something really bad can happen here like a segmentation fault
            # because we may free some memory twice
            raise AssertionError("Already destroyed")
        self.del_calls += 1

        # Simulate an error
        raise ValueError("Error while destroying the object")


class MyCorrectObject(object):
    def __init__(self):
        self.del_calls = 0

    def __del__(self):
        if self.del_calls:
            # Something really bad can happen here like a segmentation fault
            # because we may free some memory twice
            raise AssertionError("Already destroyed")
        self.del_calls += 1

        # No error here


class TestDestructor(unittest.TestCase):
    def test_my_correct_object_should_destroy_itself(self):
        # Given
        my_object = MyCorrectObject()

        # When / Then
        del my_object
        gc.collect()

    # This test should fail
    def test_my_wrong_object_should_destroy_itself(self):
        # Given
        my_object = MyWrongObject()

        # When / Then
        del my_object
        gc.collect()

В текущем состоянии оба теста пройдены успешно, а второй выводит ValueError в стандартный вывод:

python -m unittest snips_nlu.tests.test_destructor.TestDestructor                                                                                                     1 ↵
.Exception ignored in: <bound method MyWrongObject.__del__ of <snips_nlu.tests.test_destructor.MyWrongObject object at 0x1118bbda0>>
Traceback (most recent call last):
  File "/Users/adrien/dev/snips-nlu/snips_nlu/tests/test_destructor.py", line 17, in __del__
    raise ValueError("Error while destroying the object")
ValueError: Error while destroying the object
.
----------------------------------------------------------------------
Ran 2 tests in 0.044s

OK

Я могуне удается написать эти тесты согласованным образом (используя один и тот же код в обоих) и выполнить первый проход, в то время как второй выходит из строя (без AssertionError в stdout).

Спасибо заваша помощь!

...