Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Signal/Slot problems in QTest
Forum Updated to NodeBB v4.3 + New Features

Signal/Slot problems in QTest

Scheduled Pinned Locked Moved Unsolved General and Desktop
20 Posts 5 Posters 2.8k Views 3 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • HowardHarknessH Offline
    HowardHarknessH Offline
    HowardHarkness
    wrote on last edited by
    #1

    I'm writing an application which sends commands (UDP) to hardware, which returns data answers (UDP).

    I have looked at a couple of posts that I thought might apply to this, but they weren't exactly what I was searching for.

    The problem I'm having is that during a normal run of the application, I get the data back using a slot, but in my attempt at unit testing, the slot never gets called.

    The connect code looks like this:

    	// Tie readyRead Signal to readPendingDatagrams Slot
    	connect(udpSocket,
    	        &QUdpSocket::readyRead,
    	        this,
    	        &Sender::readPendingDatagrams
    	        );    
    

    The Sender class looks like this:

    	class Sender : public QObject
    	{
    	Q_OBJECT
    	public:
    		explicit Sender(Ui::MainWindow* mainwindow);
    		bool createPCSocket(QHostAddress ipAddress, quint16 port);
    		qint64 sendPacket(QNetworkDatagram datagram);
    
    	private slots:
    		void readPendingDatagrams();
    
    	private:
    		Ui::MainWindow   *ui;
    		QByteArray        buffer;
    		QUdpSocket       *udpSocket;
    
    		// for unit test
    		friend class tst_udp_connection;
    	};
    

    Definition of readPendingDatagrams() is:

    	void Sender::readPendingDatagrams()
    	{
    		static quint16 currentPacketNumber(0);
    		// when data comes inMiscRegisterGroup
    		uint byteCount = udpSocket->pendingDatagramSize();
    		buffer.resize(byteCount);
    
    		QHostAddress senderAddress;
    		quint16 senderPort;
    		if(udpSocket->readDatagram(buffer.data(), buffer.size(),
    							 &senderAddress, &senderPort) > 0)
    		{
    			formatUtilities::endianAdjust(buffer);
    		}
    

    ...and so forth.

    Using the debugger, I verified that the connect call is being made from the unit test when I execute a simulated button press, but the signal is not issued when I issued the read command. I worked around this by explicitly calling readPendingDatagrams() after the send command button click:

    	ui->sendCommandButton->click();
    	sender->readPendingDatagrams();
    

    This doesn't seem to me like something I should need to do, so my conclusion is that I am missing something important -- or just not understanding how to properly set up my unit tests.

    Summary: In unit test code, I'm not getting the callback to readPendingDatagrams(). In regular (non unit test) code, the signals/slots behave as expected. So, what am I doing wrong?

    Howard Lee Harkness
    https://howardleeharkness.com/resume
    Current contract ends on March 11th, 2022 -- Looking for C++ Real-time Embedded Systems work

    1 Reply Last reply
    0
    • Christian EhrlicherC Online
      Christian EhrlicherC Online
      Christian Ehrlicher
      Lifetime Qt Champion
      wrote on last edited by
      #2

      You have to wait until the data arrived. Simply reading data without the notification that data arrived will not work. See QTest::qWaitFor() and/or QSignalSpy

      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
      Visit the Qt Academy at https://academy.qt.io/catalog

      HowardHarknessH 1 Reply Last reply
      3
      • Christian EhrlicherC Christian Ehrlicher

        You have to wait until the data arrived. Simply reading data without the notification that data arrived will not work. See QTest::qWaitFor() and/or QSignalSpy

        HowardHarknessH Offline
        HowardHarknessH Offline
        HowardHarkness
        wrote on last edited by
        #3

        @Christian-Ehrlicher said in Signal/Slot problems in QTest:

        You have to wait until the data arrived.

        I don't understand that at all. The function readPendingDatagrams() is basically a callback. It should get called as soon as the input packet is ready -- which is what it does in the application.

        In the unit test, unless I explicitly call it (the explicit call to readPendingDatagrams() shown in my original post works without any explicit wait, indicating that the return packet is coming back very quickly), it never gets called. Using WireShark, I see the packet coming in, but the slot is not called.

        As an additional verification, I added a flag to the Sender class, and had readPendingDatagrams() set it so I can detect when readPendingDatagrams() was called.

        ui->sendCommandButton->click();
        while(!sender->isPacketReady())
        {
        	QTest::qWait(1);
        }
        

        The unit test hangs forever on the while-loop. The slot is never called.

        Howard Lee Harkness
        https://howardleeharkness.com/resume
        Current contract ends on March 11th, 2022 -- Looking for C++ Real-time Embedded Systems work

        1 Reply Last reply
        0
        • Christian EhrlicherC Online
          Christian EhrlicherC Online
          Christian Ehrlicher
          Lifetime Qt Champion
          wrote on last edited by
          #4

          @HowardHarkness said in Signal/Slot problems in QTest:

          In the unit test, unless I explicitly call it (the explicit call to readPendingDatagrams() shown in my original post works without any explicit wait, indicating that the return packet is coming back very quickly), it never gets called.

          Sorry but re-read this sentence and then tell me again what your problem is.

          Also what for instance does sendCommandButton() do? Please show us the full but simplified code.

          Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
          Visit the Qt Academy at https://academy.qt.io/catalog

          Pl45m4P HowardHarknessH 2 Replies Last reply
          0
          • Christian EhrlicherC Christian Ehrlicher

            @HowardHarkness said in Signal/Slot problems in QTest:

            In the unit test, unless I explicitly call it (the explicit call to readPendingDatagrams() shown in my original post works without any explicit wait, indicating that the return packet is coming back very quickly), it never gets called.

            Sorry but re-read this sentence and then tell me again what your problem is.

            Also what for instance does sendCommandButton() do? Please show us the full but simplified code.

            Pl45m4P Offline
            Pl45m4P Offline
            Pl45m4
            wrote on last edited by Pl45m4
            #5

            @Christian-Ehrlicher said in Signal/Slot problems in QTest:

            Also what for instance does sendCommandButton() do?

            I think it's a QPushbutton on which a click() is simulated during the QTest.
            [Edit: You probably know that... :) Misunderstood your question :) ]

            @HowardHarkness
            But @Christian-Ehrlicher is right, nobody can see from your example when, for instance, isPacketReady() becomes true since it's not shown in your header or your code file snippet :)
            Just looked up qWait(int ms)... this, at least is not the problem, since the documentation states:

            While waiting, events will be processed and your test will stay responsive to user interface events or network communication.


            If debugging is the process of removing software bugs, then programming must be the process of putting them in.

            ~E. W. Dijkstra

            HowardHarknessH 1 Reply Last reply
            0
            • Christian EhrlicherC Christian Ehrlicher

              @HowardHarkness said in Signal/Slot problems in QTest:

              In the unit test, unless I explicitly call it (the explicit call to readPendingDatagrams() shown in my original post works without any explicit wait, indicating that the return packet is coming back very quickly), it never gets called.

              Sorry but re-read this sentence and then tell me again what your problem is.

              Also what for instance does sendCommandButton() do? Please show us the full but simplified code.

              HowardHarknessH Offline
              HowardHarknessH Offline
              HowardHarkness
              wrote on last edited by
              #6

              @Christian-Ehrlicher said in Signal/Slot problems in QTest:

              Sorry but re-read this sentence and then tell me again what your problem is.

              . In the normal application, the slot handler gets called normally.
              . In the unit test, the slot handler never gets called unless I make an explicit call to it.

              Also what for instance does sendCommandButton() do? Please show us the full but simplified code.
              Ok, here's the handler for the send command button, with most of the fluff elided.

              void MainWindow::on_sendCommandButton_clicked()
              {
              	uint commandLineCount(ui->wordCountLineEdit->text().toUInt(nullptr, baseHex));
              	... error condition checks for initial setup
              	else // setup was completed normally
              	{
              		// actual number of lines may differ from the value in wordCountLineEdit
              		QStringList lines(udpPayload.split('\n'));
              		... pad out the payload to 20 bytes for the eval board
              		QString updData(ui->updOutputPlainTextEdit->toPlainText().replace("\n", ""));
              		QByteArray transmitData(QByteArray::fromHex(updData.toUtf8()));
              
              		QNetworkDatagram datagram(transmitData, evalBoardIp, evalBoardPort);
              		quint64 bytesTransmitted = sender->sendPacket(datagram);
              	... compose & display confirmation or failure message in status bar
              	}
              	ui->updInputPlainTextEdit->clear();
              }
              

              The "setup was completed normally" section does get executed, as verified with WireShark, the debugger, and the status bar confirmation message.

              Howard Lee Harkness
              https://howardleeharkness.com/resume
              Current contract ends on March 11th, 2022 -- Looking for C++ Real-time Embedded Systems work

              1 Reply Last reply
              0
              • Pl45m4P Pl45m4

                @Christian-Ehrlicher said in Signal/Slot problems in QTest:

                Also what for instance does sendCommandButton() do?

                I think it's a QPushbutton on which a click() is simulated during the QTest.
                [Edit: You probably know that... :) Misunderstood your question :) ]

                @HowardHarkness
                But @Christian-Ehrlicher is right, nobody can see from your example when, for instance, isPacketReady() becomes true since it's not shown in your header or your code file snippet :)
                Just looked up qWait(int ms)... this, at least is not the problem, since the documentation states:

                While waiting, events will be processed and your test will stay responsive to user interface events or network communication.

                HowardHarknessH Offline
                HowardHarknessH Offline
                HowardHarkness
                wrote on last edited by
                #7

                @Pl45m4 said in Signal/Slot problems in QTest:

                nobody can see from your example when, for instance, isPacketReady() becomes true

                I defined a bool packetReady; in the Sender class, and set it false in the ctor.
                The last line of readPendingDatagrams() is "packetReady = true;" to indicate that it has been called.
                Function isPacketReady() returns the value of packetReady -- which is never true, since the slot handler readPendingDatagrams() is never called.

                Howard Lee Harkness
                https://howardleeharkness.com/resume
                Current contract ends on March 11th, 2022 -- Looking for C++ Real-time Embedded Systems work

                1 Reply Last reply
                0
                • Christian EhrlicherC Online
                  Christian EhrlicherC Online
                  Christian Ehrlicher
                  Lifetime Qt Champion
                  wrote on last edited by Christian Ehrlicher
                  #8

                  This works fine for me

                  class tst_Udp : public QObject
                  {
                    Q_OBJECT
                  private Q_SLOTS:
                    void testSendReceiveUdp();
                  };
                  
                  void tst_Udp::testSendReceiveUdp()
                  {
                    QUdpSocket sender;
                    QUdpSocket receiver;
                    bool packetReceived = false;
                    QByteArray buf;
                    connect(&receiver, &QUdpSocket::readyRead, [&]() {
                      if (receiver.hasPendingDatagrams()) {
                        buf.resize(receiver.pendingDatagramSize());
                        receiver.readDatagram(buf.data(), buf.size());
                        qDebug() << "Received: " << buf;
                        packetReceived = true;
                      }
                    });
                    receiver.bind(QHostAddress("127.0.0.1"), 12345);
                    QTimer::singleShot(0, this, [&]() {
                      sender.writeDatagram(QByteArray("Hello!"), QHostAddress("127.0.0.1"), 12345);
                    });
                    while (!packetReceived) {
                      QTest::qWait(100);
                      qDebug() << "Waiting...";
                    }
                    qDebug() << "Finished";
                  }
                  
                  QTEST_MAIN(tst_Udp)
                  

                  Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                  Visit the Qt Academy at https://academy.qt.io/catalog

                  HowardHarknessH 1 Reply Last reply
                  1
                  • Christian EhrlicherC Christian Ehrlicher

                    This works fine for me

                    class tst_Udp : public QObject
                    {
                      Q_OBJECT
                    private Q_SLOTS:
                      void testSendReceiveUdp();
                    };
                    
                    void tst_Udp::testSendReceiveUdp()
                    {
                      QUdpSocket sender;
                      QUdpSocket receiver;
                      bool packetReceived = false;
                      QByteArray buf;
                      connect(&receiver, &QUdpSocket::readyRead, [&]() {
                        if (receiver.hasPendingDatagrams()) {
                          buf.resize(receiver.pendingDatagramSize());
                          receiver.readDatagram(buf.data(), buf.size());
                          qDebug() << "Received: " << buf;
                          packetReceived = true;
                        }
                      });
                      receiver.bind(QHostAddress("127.0.0.1"), 12345);
                      QTimer::singleShot(0, this, [&]() {
                        sender.writeDatagram(QByteArray("Hello!"), QHostAddress("127.0.0.1"), 12345);
                      });
                      while (!packetReceived) {
                        QTest::qWait(100);
                        qDebug() << "Waiting...";
                      }
                      qDebug() << "Finished";
                    }
                    
                    QTEST_MAIN(tst_Udp)
                    
                    HowardHarknessH Offline
                    HowardHarknessH Offline
                    HowardHarkness
                    wrote on last edited by
                    #9

                    @Christian-Ehrlicher Does that mean that I have to do the connect() call in the unit test case?

                    I'm still a bit confused. The connect() does happen in the unit test setup, as confirmed using the debugger.

                    I'll be examining this in more depth after I figure out how to solve my other problem with Ui::MainWindow access...

                    Howard Lee Harkness
                    https://howardleeharkness.com/resume
                    Current contract ends on March 11th, 2022 -- Looking for C++ Real-time Embedded Systems work

                    Christian EhrlicherC 1 Reply Last reply
                    0
                    • HowardHarknessH HowardHarkness

                      @Christian-Ehrlicher Does that mean that I have to do the connect() call in the unit test case?

                      I'm still a bit confused. The connect() does happen in the unit test setup, as confirmed using the debugger.

                      I'll be examining this in more depth after I figure out how to solve my other problem with Ui::MainWindow access...

                      Christian EhrlicherC Online
                      Christian EhrlicherC Online
                      Christian Ehrlicher
                      Lifetime Qt Champion
                      wrote on last edited by
                      #10

                      @HowardHarkness said in Signal/Slot problems in QTest:

                      Does that mean that I have to do the connect() call in the unit test case?

                      Somewhere in your code you have to call the connect, yes. How else should the slot be called?

                      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                      Visit the Qt Academy at https://academy.qt.io/catalog

                      HowardHarknessH 1 Reply Last reply
                      0
                      • Christian EhrlicherC Christian Ehrlicher

                        @HowardHarkness said in Signal/Slot problems in QTest:

                        Does that mean that I have to do the connect() call in the unit test case?

                        Somewhere in your code you have to call the connect, yes. How else should the slot be called?

                        HowardHarknessH Offline
                        HowardHarknessH Offline
                        HowardHarkness
                        wrote on last edited by
                        #11

                        @Christian-Ehrlicher The problem is that the slot is not called at all in the unit test.

                        Howard Lee Harkness
                        https://howardleeharkness.com/resume
                        Current contract ends on March 11th, 2022 -- Looking for C++ Real-time Embedded Systems work

                        Christian EhrlicherC 1 Reply Last reply
                        0
                        • HowardHarknessH HowardHarkness

                          @Christian-Ehrlicher The problem is that the slot is not called at all in the unit test.

                          Christian EhrlicherC Online
                          Christian EhrlicherC Online
                          Christian Ehrlicher
                          Lifetime Qt Champion
                          wrote on last edited by
                          #12

                          @HowardHarkness You have a unittest which works - I don't know what you're doing in your code. A slot can only be called when a signal is connected to it.

                          Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                          Visit the Qt Academy at https://academy.qt.io/catalog

                          HowardHarknessH 1 Reply Last reply
                          0
                          • Christian EhrlicherC Christian Ehrlicher

                            @HowardHarkness You have a unittest which works - I don't know what you're doing in your code. A slot can only be called when a signal is connected to it.

                            HowardHarknessH Offline
                            HowardHarknessH Offline
                            HowardHarkness
                            wrote on last edited by
                            #13

                            @Christian-Ehrlicher said in Signal/Slot problems in QTest:

                            A slot can only be called when a signal is connected to it.

                            The slot is connected, but does not get called unless I insert an explicit call to the read function. I suspect this is a red herring, and the real problem is elsewhere. Inserting the explicit call is the workaround that makes the unit test work. Meanwhile, I'm working on another problem (a poor design decision, which might actually impact this).

                            Howard Lee Harkness
                            https://howardleeharkness.com/resume
                            Current contract ends on March 11th, 2022 -- Looking for C++ Real-time Embedded Systems work

                            1 Reply Last reply
                            0
                            • M Offline
                              M Offline
                              mchinand
                              wrote on last edited by
                              #14

                              You could use a QSignalSpy to check that the signal is actually being emitted during your test. Also, make sure you are connecting the correct instances of your respective classes.

                              HowardHarknessH 1 Reply Last reply
                              0
                              • M mchinand

                                You could use a QSignalSpy to check that the signal is actually being emitted during your test. Also, make sure you are connecting the correct instances of your respective classes.

                                HowardHarknessH Offline
                                HowardHarknessH Offline
                                HowardHarkness
                                wrote on last edited by HowardHarkness
                                #15

                                Well, I'm back from COVID recovery, and still have this problem.
                                I tried the "poor man's" unit test framework -- I created a dialog with an output report and some buttons to run tests on the mainwindow. I was surprised to run into exactly the same problem, in exactly the same place, for what appears to be the same reason.

                                In my test, I click on a button that should send a command to the hardware, which will respond with a reply packet.

                                // send read command
                                   btnSendCommand->click();
                                

                                It appears that the signal for the read never gets sent.

                                However, if I actually click on that button with my mouse, it works, and I get the expected input.

                                I have to conclude one of the following:

                                1. The btnSendCommand->click(); does not actually do the same thing as using the mouse to click the button.
                                2. There is some environmental issue I am getting wrong in my test.
                                3. There is a timing issue I don't understand.

                                Howard Lee Harkness
                                https://howardleeharkness.com/resume
                                Current contract ends on March 11th, 2022 -- Looking for C++ Real-time Embedded Systems work

                                Pl45m4P 1 Reply Last reply
                                0
                                • HowardHarknessH HowardHarkness

                                  Well, I'm back from COVID recovery, and still have this problem.
                                  I tried the "poor man's" unit test framework -- I created a dialog with an output report and some buttons to run tests on the mainwindow. I was surprised to run into exactly the same problem, in exactly the same place, for what appears to be the same reason.

                                  In my test, I click on a button that should send a command to the hardware, which will respond with a reply packet.

                                  // send read command
                                     btnSendCommand->click();
                                  

                                  It appears that the signal for the read never gets sent.

                                  However, if I actually click on that button with my mouse, it works, and I get the expected input.

                                  I have to conclude one of the following:

                                  1. The btnSendCommand->click(); does not actually do the same thing as using the mouse to click the button.
                                  2. There is some environmental issue I am getting wrong in my test.
                                  3. There is a timing issue I don't understand.
                                  Pl45m4P Offline
                                  Pl45m4P Offline
                                  Pl45m4
                                  wrote on last edited by Pl45m4
                                  #16

                                  @HowardHarkness said in Signal/Slot problems in QTest:

                                  The btnSendCommand->click(); does not actually do the same thing as using the mouse to click the button.

                                  What if you "focus" the button first, before you virtually click it? (for example with setFocus).
                                  What if you click it twice by code?
                                  Just a guess...you could try it.

                                  • https://code.woboq.org/qt5/qtbase/src/widgets/widgets/qabstractbutton.cpp.html#_ZN15QAbstractButton5clickEv

                                  Have you tried animateClick ()?

                                  • https://code.woboq.org/qt5/qtbase/src/widgets/widgets/qabstractbutton.cpp.html#_ZN15QAbstractButton12animateClickEi

                                  If debugging is the process of removing software bugs, then programming must be the process of putting them in.

                                  ~E. W. Dijkstra

                                  HowardHarknessH 1 Reply Last reply
                                  0
                                  • Pl45m4P Pl45m4

                                    @HowardHarkness said in Signal/Slot problems in QTest:

                                    The btnSendCommand->click(); does not actually do the same thing as using the mouse to click the button.

                                    What if you "focus" the button first, before you virtually click it? (for example with setFocus).
                                    What if you click it twice by code?
                                    Just a guess...you could try it.

                                    • https://code.woboq.org/qt5/qtbase/src/widgets/widgets/qabstractbutton.cpp.html#_ZN15QAbstractButton5clickEv

                                    Have you tried animateClick ()?

                                    • https://code.woboq.org/qt5/qtbase/src/widgets/widgets/qabstractbutton.cpp.html#_ZN15QAbstractButton12animateClickEi
                                    HowardHarknessH Offline
                                    HowardHarknessH Offline
                                    HowardHarkness
                                    wrote on last edited by
                                    #17

                                    @Pl45m4 Ok, I tried focus(). No difference. I tried multiple calls to click(). No difference. As for animateClick(), I didn't see any difference, but I'm wondering if I need to add some sort of delay to wait for completion.

                                    I put some tracing code in the slot handler, and discovered that the first time I invoke the test function, the slot handler is not called. The second time I invoke the test function, the slot IS called, but the results aren't available in time for my checks. So, the THIRD time I invoke the test function, the test results are as expected.

                                    So, I think I have narrowed it down to a timing problem. Not sure how to address that yet.

                                    Howard Lee Harkness
                                    https://howardleeharkness.com/resume
                                    Current contract ends on March 11th, 2022 -- Looking for C++ Real-time Embedded Systems work

                                    HowardHarknessH 1 Reply Last reply
                                    0
                                    • HowardHarknessH HowardHarkness

                                      @Pl45m4 Ok, I tried focus(). No difference. I tried multiple calls to click(). No difference. As for animateClick(), I didn't see any difference, but I'm wondering if I need to add some sort of delay to wait for completion.

                                      I put some tracing code in the slot handler, and discovered that the first time I invoke the test function, the slot handler is not called. The second time I invoke the test function, the slot IS called, but the results aren't available in time for my checks. So, the THIRD time I invoke the test function, the test results are as expected.

                                      So, I think I have narrowed it down to a timing problem. Not sure how to address that yet.

                                      HowardHarknessH Offline
                                      HowardHarknessH Offline
                                      HowardHarkness
                                      wrote on last edited by
                                      #18

                                      Ah, I have narrowed it down to some sort of timing or thread conflict. Invoking the test function by hand 3 times has the effect noted above (1. No slot call, 2. Slot call, but updates don't happen in time, 3. Success).
                                      However if I just invoke the test function three times in code, the result is no slot call.

                                      Howard Lee Harkness
                                      https://howardleeharkness.com/resume
                                      Current contract ends on March 11th, 2022 -- Looking for C++ Real-time Embedded Systems work

                                      1 Reply Last reply
                                      0
                                      • 6thC6 Offline
                                        6thC6 Offline
                                        6thC
                                        wrote on last edited by
                                        #19

                                        Did you ever get to the bottom of this?

                                        We have the same symptoms with seeing packets in wireshark but readyRead() not triggering, even if I manually check hasPendingDatagrams() after, for immediate replies QUdpSocket just doesn't get the message.

                                        HowardHarknessH 1 Reply Last reply
                                        0
                                        • 6thC6 6thC

                                          Did you ever get to the bottom of this?

                                          We have the same symptoms with seeing packets in wireshark but readyRead() not triggering, even if I manually check hasPendingDatagrams() after, for immediate replies QUdpSocket just doesn't get the message.

                                          HowardHarknessH Offline
                                          HowardHarknessH Offline
                                          HowardHarkness
                                          wrote on last edited by
                                          #20

                                          @6thC Yes, I did.

                                          I'm no longer on that project, but I recall that it was basically a typo. I was not properly setting up the correct slot. Totally my screwup.

                                          Howard Lee Harkness
                                          https://howardleeharkness.com/resume
                                          Current contract ends on March 11th, 2022 -- Looking for C++ Real-time Embedded Systems work

                                          1 Reply Last reply
                                          0

                                          • Login

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • Users
                                          • Groups
                                          • Search
                                          • Get Qt Extensions
                                          • Unsolved