QSignalSpy verify emission order
-
Is there any way to verify in which order signals were emitted?
I have a method which emits one signal on start and another when ending.
class MyClass: public QObject { Q_OBJECT public: void doSomething() { emit started(); // Do something here emit finished(); } signals: void started(); void finished(); };
I want to write a test to ensure that they are emitted in the correct order. I can create two
QSignalSpy
s to verify that each signal is emitted, however I don't see anything to validate the order in which that would have happened.MyClass inst; QSignalSpy startedSpy(&inst, SIGNAL(started()); QSignalSpy finishedSpy(&inst, SIGNAL(finished()); inst.doSomething(); QCOMPARE(startedSpy.count(), 1); // Verify that the "something" of the method took place QCOMPARE(finishedSpy.count(), 1);
The only thing that I can see would be merging the two signals into one and using a parameter to differentiate them. Thus a single
QSignalSpy
could be used, and I could then validate their order that way, but that's not a design choice that I want to make use of in the code under test. Is there any other means of achieving this? -
You don't have to use QSignalSpy, you could store the received signals in an ordered list:
QStringList receivedSignals; QObject::connect(&inst, &MyClass::started, &inst, [&] { receivedSignals.append("started"); }); QObject::connect(&inst, &MyClass::finished, &inst, [&] { receivedSignals.append("finished"); }); inst.doSomething(); QStringList expectedSignals = {"started", "finished"}; QCOMPARE(receivedSignals, expectedSignals);
-
Why do you want to write a unittest for such a thing?
https://doc.qt.io/qt-6/signalsandslots.html#signals
When a signal is emitted, the slots connected to it are usually executed immediately, just like a normal function call.
-
Mainly as a sanity test and as a "regression" to guard against future edits causing grief. I can visually inspect that the two signals are emitted in the expected order, but if I can encode that in a test, then it can protect against someone doing something to break this order in the future. My "concern" is not with the slots being delayed in execution for whatever reason, but at some point someone mistakenly causing
finished()
to be emitted beforestarted()
. -
You don't have to use QSignalSpy, you could store the received signals in an ordered list:
QStringList receivedSignals; QObject::connect(&inst, &MyClass::started, &inst, [&] { receivedSignals.append("started"); }); QObject::connect(&inst, &MyClass::finished, &inst, [&] { receivedSignals.append("finished"); }); inst.doSomething(); QStringList expectedSignals = {"started", "finished"}; QCOMPARE(receivedSignals, expectedSignals);
-
@cancech said in QSignalSpy verify emission order:
Mainly as a sanity test and as a "regression" to guard against future edits causing grief.
Then this would be a newly introduced Qt bug and a serious bug in the system - how should the order change in any way for a DirectConnection?
I would rather concentrate on really important tests than trying to test the underlying library though. -
@Christian-Ehrlicher said in QSignalSpy verify emission order:
@cancech said in QSignalSpy verify emission order:
Mainly as a sanity test and as a "regression" to guard against future edits causing grief.
Then this would be a newly introduced Qt bug and a serious bug in the system - how should the order change in any way for a DirectConnection?
I would rather concentrate on really important tests than trying to test the underlying library though.I'm not thinking about testing the library, but rather my code. I want to make sure that in my code the
started()
signal is emitted beforefinished()
. I can perform a visual inspection to see that that is currently happening, but codifying it in a test would allow for ensuring that this continues to be the case as people (including myself) make changes to the code into the future.I've been bitten far too many times by careless oversights causing a change in the order of operations where technically things still happen, but the changing of their order has ripple effects that then take a very long time to debug. If I can add a simple test right away to ensure that this order is maintained, then that has the potential to save a lot of grief down the road :-)
-
Then, based on GrecKo's answer:
QStringList receivedSignals; bool receivedStart = false; bool receivedFinished = false; QObject::connect(&inst, &MyClass::started, &inst, [&] { receivedStart = true; QVERIFY(!receivedFinished); }); QObject::connect(&inst, &MyClass::finished, &inst, [&] { receivedFinished = true; QVERIFY(receivedStart); }); inst.doSomething();
-
@GrecKo said in QSignalSpy verify emission order:
You don't have to use QSignalSpy, you could store the received signals in an ordered list:
QStringList receivedSignals; QObject::connect(&inst, &MyClass::started, &inst, [&] { receivedSignals.append("started"); }); QObject::connect(&inst, &MyClass::finished, &inst, [&] { receivedSignals.append("finished"); }); inst.doSomething(); QStringList expectedSignals = {"started", "finished"}; QCOMPARE(receivedSignals, expectedSignals);
That makes sense. I figured that using an external mechanism would do the trick, though your idea with a lambda populating a
QStringList
is far simpler than what I was cooking up. I was hoping for a simple solution, and this looks like it'll be the simplest way of achieving my goal.Thanks!
-