I'm trying to make some unit tests for a pyqt5 application. The problem is that I cannot run multiple tests in a test suite because I'm not clearning up the application properly and the end of every test.
class MainWindowTest(QMainWindow):
def __init__(self, widgetTypeUnderTest=None, model=None):
super().__init__()
self.widgetTypeUnderTest = widgetTypeUnderTest
self.model = model
# setting title
self.setWindowTitle("AccosTest")
self.setGeometry(100, 100, 500, 600)
self.mainWindowLayout = QHBoxLayout()
# container widget for everything else
widget = QWidget()
widget.setLayout(self.mainWindowLayout)
self.setCentralWidget(widget)
self.show()
class Tests(unittest.TestCase):
def setUp(self) -> None:
self.app = QApplication(sys.argv)
def tearDown(self) -> None:
self.app.exit()
def test(self):
mainWindow = MainWindowTest()
def test2(self):
mainWindow = MainWindowTest()
Runing Tests.test1
or Tests.test2
individually does what is required, although this is likely because a second QApplication
has not been started. When running both tests together I get a segfault.
Would anybody know the correct commands to properly dismantle the QApplication
after every test, since self.app.exit()
doesn't seem to be doing the trick. Thanks!
edit
Do you think a better strategy would be to have two threads. One would start the main loop sys.exit(self.app.exec())
and the other would wait for a while and then call exit?
CodePudding user response:
There is normally no need to recreate a QApplication, even for testing (unless you do need to make multiple tests for the behavior of the program when the application is started or quit).
You can get the current existing QApplication using instance()
:
def setUp(self) -> None:
self.app = QApplication.instance() or QApplication.(sys.argv)
In the rare case for which you really need to restart the application, then you need to ensure that the previous application has really been quit. Since that presumes the fact that exec()
has been called, you can then destroy the app
reference and recreate it again.
Note that you cannot create another application outside of the main thread (or, to be precise, outside the thread in which the first application was created).
CodePudding user response:
Thanks to @musicamante for the answer.
Here it is in code:
Option 1
Use the destructor, using del
in python.
class MainWindowTest(QMainWindow):
def __init__(self, widgetTypeUnderTest=None, model=None):
super().__init__()
self.widgetTypeUnderTest = widgetTypeUnderTest
self.model = model
# setting title
self.setWindowTitle("AccosTest")
self.setGeometry(100, 100, 500, 600)
self.mainWindowLayout = QHBoxLayout()
# container widget for everything else
widget = QWidget()
widget.setLayout(self.mainWindowLayout)
self.setCentralWidget(widget)
self.show()
class Tests(unittest.TestCase):
def setUp(self) -> None:
self.app = QApplication(sys.argv)
def tearDown(self) -> None:
del self.app
def test(self):
mainWindow = MainWindowTest()
def test2(self):
mainWindow = MainWindowTest()
Option 2
Make QApplication
global and
app = QApplication(sys.argv)
class Tests(unittest.TestCase):
def setUp(self) -> None:
self.app = app.instance()
def tearDown(self) -> None:
self.app.closeAllWindows()
def test(self):
mainWindow = MainWindowTest()
def test2(self):
mainWindow = MainWindowTest()
It seems that Option 2
should be preferred because you shouldn't need to make and destroy the QApplication
after every test. However, my personal preference is Option 1
to keep unit tests completely independent.