У кого-нибудь есть объяснение, почему следующая память утечек (память и другие объекты ядра, такие как GDI и пользовательские ручки, продолжают увеличиваться на каждой итерации и никогда не возвращаются вниз до тестовых выходов):Мемная утечка в тесте pyqt с pytest
import pytest
from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import QApplication, QGraphicsScene, QGraphicsView
class TestCase:
@pytest.mark.parametrize('dummy', range(1000))
def test_empty(self, dummy):
# self.view = None # does NOT fix the leak if uncommented!
self.app = QApplication.instance()
if self.app is None:
self.app = QApplication([])
self.view = QGraphicsView()
self.view.setFixedSize(600, 400)
self.view.setScene(QGraphicsScene())
self.view.show()
QTimer.singleShot(100, self.app.exit)
self.app.exec()
# self.view = None # FIXES the leak if uncommented!
Там нет утечки, если какой-либо из следующих условий становится True:
- Если я None-римента вид перед метод испытания возвращает (раскомментировать последнюю строку)
- Если я сделаю вид локальным для функции вместо члена self (не удивительно, данное исправление № 1)
- Если я удаляю декоратор и , вместо этого вместо «while True» в верхней части функции (так тест сам запускается один раз, но окно пересоздался снова и снова)
Интересно, что утечка не уходит, если я делать какие-либо из следующих модификаций:
- Я поставил точку зрения на None в начале функции, а не в конце (прокомментированная строка в ginning метода испытания)
- Вместо того, чтобы параметризовать метод тестирования, я создаю множество методов тестирования (100, легко выполняемых с помощью небольшого скрипта python, который генерирует тестовый модуль) или многих тестовых классов, многих тестовых модулей (так я заметил проблема состоит в том, что у нас есть огромный набор тестов, состоящий из 100 тестовых модулей с несколькими классами в каждом, каждый из которых имеет множество методов тестирования - утечка памяти в наборе тестов осталась незамеченной до недавнего времени, когда количество тестов стало достаточно большим, теперь заканчивается обработка дескрипторов GDI до завершения тестирования pytest!).
- я заменить вызов на одного выстрела в app.exit() по app.closeAllWindows() (я думал, что это, возможно, был вопрос в этом MCVE)
Фактические испытания в нашем приложении требуют, чтобы некоторые объекты создаются в setup_method(), поэтому мы не можем избежать назначения объектов PyQt членам данных тестового экземпляра. Итак, единственное практическое решение для нас - это отредактировать каждый метод тестирования объектам PyQt None-ify, созданным этими методами, но это будет подвержено ошибкам, не говоря уже о трудоемком (хотя и лучше, чем в текущей ситуации). Я надеюсь, что есть лучший способ.
Вид не имеет права собственности на сцену, поэтому вы должны держать ссылку на него. – ekhumoro
@ekhumoro Да, настоящий код делает это. Фактически, вы можете удалить строку с помощью setScene(), и у вас все еще будет утечка. – Schollii
См. Также https://github.com/pytest-dev/pytest/issues/1649 – dbn