To perform unitary tests on the following part of a code (I use ...
to replace unnecessary things to simplify)
from PyQt5.QtWidgets import QWidget, QLineEdit
// ...
class Controller(QWidget):
def __init__(self, ...)
// ...
self.line_edit_name = QLineEdit()
// ...
def display_parameters(self, name, ...)
self.line_edit_name.setText(name)
self.line_edit_name.setReadOnly(False)
self.line_edit_name.returnPressed.connect(
partial(self.update_name, ...))
def update_name(self, ...):
// ...
I use this piece of code for tests using unittest:
from PyQt5 import QtCore, QtGui
from PyQt5.QtCore import QCoreApplication, QEvent
// ...
a = Controller()
a.line_edit_name.setText("Shakespeare")
keyEvent = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, QtCore.Qt.Key_Return, QtCore.Qt.NoModifier)
QCoreApplication.postEvent(a.line_edit_name, keyEvent)
// ...
it worked very well during the debugging phase (I use input('foo') a lot to introspect and see step by step what is going on) ...
But if I remove the input function it doesn't work anymore !!!!
In summary: the following script gives the right result
a = Controller()
a.line_edit_name.setText("Shakespeare")
keyEvent = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, QtCore.Qt.Key_Return, QtCore.Qt.NoModifier)
QCoreApplication.postEvent(a.line_edit_name, keyEvent)
input("foo")
//...
the following not
a = Controller()
a.line_edit_name.setText("Shakespeare")
keyEvent = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, QtCore.Qt.Key_Return, QtCore.Qt.NoModifier)
QCoreApplication.postEvent(a.line_edit_name, keyEvent)
// ...
Because unit tests are done automatically during continuous integration we cannot use the input function. Why this result and how to do without input function?
Edit: By doing various tests I think that the input() function just allows processes to finish before the next command. I tried just after QCoreApplication.postEvent(a.line_edit_name, keyEvent)
, in place of input("foo")
, threading.Event().wait(1)
or time.sleep(1)
without success ...
CodePudding user response:
In Qt, the task of sending the event and invoking the slots associated with signals is asynchronous, so do not expect to get a response instantly, but you must wait. In this case you must use QTest.qWait.
Since you do not provide an MRE then I will only show a simple demo:
from functools import partial
from PyQt5.QtCore import QCoreApplication, QEvent, Qt
from PyQt5.QtGui import QKeyEvent
from PyQt5.QtWidgets import QApplication, QFormLayout, QLineEdit, QWidget
from PyQt5.QtTest import QTest
class Controller(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.current_name = ""
self.line_edit_name = QLineEdit()
lay = QFormLayout(self)
lay.addRow("name", self.line_edit_name)
def display_parameters(self, name):
self.line_edit_name.setText(name)
self.line_edit_name.setReadOnly(False)
self.line_edit_name.returnPressed.connect(partial(self.update_name, name))
def update_name(self, name):
self.current_name = name
def test_controller():
app = QApplication([])
a = Controller()
a.display_parameters("Foo")
assert a.current_name != "Foo"
keyEvent = QKeyEvent(QEvent.KeyPress, Qt.Key_Return, Qt.NoModifier)
QCoreApplication.postEvent(a.line_edit_name, keyEvent)
# QTest.keyClick(a.line_edit_name, Qt.Key_Return)
QTest.qWait(1000)
assert a.current_name == "Foo"
test_controller()
On the other hand if you want to do tests then it is better to use the QtTest submodule that already has several simplified functions besides you could use pytest-qt.