Using Boost Unit Test framework to perform unit test on C++\Qt code.
We are basically using BOOST_FIXTURE_TEST_CASE macro as shown in documentation. For each test we create an instance of QApplication to setup the event loop and enable the test code to use signals and slots.
Now we need to test whether a signal is emitted or not. Does anyone have any experience with this issue?
The BOOST_FIXTURE_TEST_CASE generated class does not inlucde Q_OBJECT and does not derived from QObject which I guess would be a problem. Appreciate some input on this issue.
I'm working on a similar issue, but using gtest rather than the Boost Unit Test framework. While I don't have the answer yet I am making progress, here is what I know so far.
First of all, Qt does not like it when QApplication or QCoreApplication are generated outside of main. Also, QApplication applies to GUI classes of Qt, while QCoreApplication can be used for console only classes (like QTcpSocket which is what I am trying to test now). GUI stuff is not really testable, so anything you are testing should be written into a separate class. This will allow you to unit test your code without dealing with the GUI, and also let you use QCoreApplication.
The next step is to use QThread to spin up a thread that hosts the object you are trying to test. QThread has its own event loop that can be run by calling its exec() function.
Write your test cases to pull from QThread and you'll have an event loop that you can use for the signals and slots, which should make it much easier to determine if a signal was emitted. Without the event loop the signal will just sit there and do nothing, so there is no way to test if it was sent!
Related
I've seen example of QApplication::notify usage here: How to detect if a Qt GUI application has been idle, inside the app itself (Qt)?
I need to do the same without basing QApplication method. qApp has connectNotify method so I suppose it should be possible just to make own action on notify signal.
If that is possible I need basic example how can I connect to this event.
Maybe you should have a look at event filters, which you can install for all QObjects: QObject::installEventFilter.
Write your own class, which you inherit from QObject and implement the eventFilter method, where you insert your event processing logic.
Then install an object of this class to your QApplication instance (qApp for example)
I am creating an modular application. It has a Core, and a few modules, amongs which is a gui module. These modules can be started via the command line:
myApp gui=qml=qmlFile.qml connection=serial=/dev/ttyS1
will start the app with one (multiple is also possible) gui and one serial connection. There is always one Router object, which handles the connection. Guis are loaded by a class that looks like this:
class Gui :QObject{
Core* core;
public:
QQmlApplicationEngine engine;
public slots:
void start(){
engine.load("qrc:/gui/from/command/line.qml");
}
In the gui i have a nice bit of qml called ConnectionController{} which is an easy way of adding/removing connections. But this is only the first of it's kind: in the end every module should have a qml component for controlling it.
This all works fine, but now i am trying to add multiple threads. I want to have a RouterThread and a GuiThread. This in itself was simply a matter of changing the creation of the Router (by the Core) to this:
m_router = new Router(this /*not as parent, just as pointer*/);
m_router->moveToThread(&routerThread);
(gui's still live in the main thread for now)
After this everything still works fine, except for qml property bindings.
QQmlEngine: Illegal attempt to connect to SerialConnection(0x7f58d00013a0) that is in a different thread than the QML engine
Because Gui and it's child QQmlEngine engine live in the guiThread while the SerialConnection lives in the routerThread.
Signals and slots between Router and Gui (without qml) do work, because they are handled by default as asynchronous by qt. (as long as the appropriate types are defined.)
Well, no, you cant access threaded objects from your gui and should not try to either.
You need to build a c++ model that lives in the main thread that is exposed to qml. Inside this model you can connect to signals emitted by your threads via a queuedconnection and link them to the models' own signals.
Also you should make sure that when you read data from an object owned by another thread, everything is properly mutexed or you will be reading garbage.
The application I'm working on is made of many C threads communicating together via messages (0mq). One of these threads is handling the display and should render off screen a widget in order to communicate its "screenshot" to other threads of the application.
The thing is that in order to paint a widget, you need to place it in a QApplication and call the exec() method of the QApplication, which is essentially a loop. So my thread is then completely stuck and can't communicate with the outside world anymore since it's in the exec() method.
Is there a way I can launch the QApplication in a separate thread and communicate with it so my display thread doesn't get stuck?
Or is there at least a way to do what I want to do with Qt?
Thanks a lot !
Edit: This application will eventually be a Qt Embedded Application
Update Basically, my question is : how to start a QApplication in a separate thread from my C code and communicate with it?
I ended up creating a separate thread for the QApplication main event loop (exec()) and used 0mq sockets to communicate with it from the rest of my application.
I don't understand what do you mean by "paint a widget". But be aware: QWidget is a part of GUI and GUI parts should be touched by Main(UI) thread only. It is a rule you can't change. Moreover QApplication works on Main thread only since QApplication is the main part of the GUI itself.
You can post messages to QAppplication by using global qApp object(you need to include QApplication for it) and sendEvent() or postEvent() methods.
Also I'd suggest you to generate QImage with whatever data you have and propagate it via aforementioned event mechanism to the widget you need. But, obviously, I don't know what you really need.
I'm using the QtSerialPort library to talk to a virtual COM port via USB. The COM port returns data and works properly when testing it with the example projects given with QtSerialPort, but fails when I run it as part of my project.
I inspected the instantiation chain and threads that lead up to the QtSerialPort being instantiated, and found something a little strange. The results are below.
main()
MainWindow (Thread 0xbf8dbe0) // Thread "A"
HardwareManager (Thread 0xbf8dbe0) // Thread "A"
QSerialPort (Thread 0xbfb95f0) // Thread "B" !?
In my code, the main() function instantiates a MainWindow, which in turn instantiates a HardwareManager and stores it as a private variable. When the HardwareManager is instantiated, it also instantiates the QSerialPort instance so it can properly talk to the COM port.
However, you'll notice above the my QSerialPort is in a different thread than the parent object, as well as it's parent object (It's in Thread B, while both ancestors are in Thread A). I think this other thread is causing my Signals/Slots to fail. If I dumpObjectInfo, it lists my Signal/Slot as being set up, but the events never fire.
this->serial = new QSerialPort();
connect(this->serial, SIGNAL(readyRead()), this, SLOT(readSerialData());
Above is the code that I use to create the new serial port and connect it to the proper slot. The actual baud, parity, and data/stop bit configuration happens separately (and works properly, as tested in the example app provided by QtSerialPort).
Does anyone have any insight as to why this particular object (QSerialPort instance) is being instantiated in a different thread? I've tried "moveToThread" to switch the thread association, but nothing seems to work.
I've also made a post on the Qt Project Forums, but have had no useful responses yet.
Edit:
The following is the relevant code in the call chain:
// main()
QApplication a(argc, argv)
MainWindow window = new MainWindow(); // [1]
MainWindow.show();
return a.exec();
// MainWindow::MainWindow() [1]
this->toolController = new QtToolController(this);
HardwareManager *manager = new HardwareManager(this->toolController); // [2]
// HardwareManager::HardwareManager() [2]
this->serial = new QSerialPort();
connect(this->serial, SIGNAL(readyRead()), this, SLOT(readSerialData()));
When a QSerialPort is ready to be read from (it has data to provide), it fires the readyRead signal (at least, it's supposed to). This signal fires properly in the Qt example projects, but I never get the signal in my application. I believe the reason I'm not getting the signal is because of these thread issues.
You could use QueuedConnection for catching signals from a different thread.
connect(this->serial, SIGNAL(readyRead()),
this, SLOT(readSerialData()), Qt::QueuedConnection);
This way, the slot should be executed in your main thread's context once the control returns to it's event loop.
Also, this post seems to suggest that you should not set a parent for the QtSerialPort (propably because moveToThread doesn't work on QObjects with parents).
In the spirit of keeping answers available to anyone else who encounters this problem, the issue was related to Release/Debug builds. The QtSerialPort library had been built ONLY for my Release environment, and for whatever reason, when running my application in Debug mode would link to the Release QtSerialPort, and thread contexts would get lost.
To fix this, I ensured I had built the proper version of the library, and then ensured I linked to the right version for my environment.
I have some code which uses WinAPI to get the title and classname of a window from it's handle using GetWindowTextW and GetClassNameW. I would like to create a unit test for this code using Qt to create a temporary window, run my code against it, and then close the window. However I'm unsure how to go about doing this in a simple way. For example, I could create the window as follows:
#include "QtWidgets\qapplication.h"
#include "QtWidgets\qtextedit.h"
int argc = 1;
char* argv[1];
QApplication app(argc, &argv[0]);
QTextEdit textEdit;
textEdit.show();
app.exec(;)
// Rest of my unit test here
However at that point the QApplication object enters it's event loop and assumes control of my unit test until I close the window. What is the best way to allow my unit test to continue operating on the window? Should I create a separate thread for the window? Being a unit test, I would like to keep it as simple as possible.
This question is intended to be unit test framework independent, but in case it matters, I'm using UnitTest++.
You won't be able to create a separate thread, since all Qt gui objects have to be in the main thread, you can only use signals/slot mechanism to interact with gui objects from other threads.
I think the simplest would be to subclass QTextEdit, implement public slot UnitTest(), and modify your test as follows:
#include "QtWidgets\qapplication.h"
#include "QtWidgets\qtextedit.h"
#include "MyTextEdit.h"
#include <QTimer>
int argc = 1;
char* argv[1];
QApplication app(argc, &argv[0]);
my_QTextEdit textEdit;
textEdit.show();
QTimer::singleShot(&my_QTextEdit,SLOT(UnitTest()),0);
app.exec();
This gives you an entry point to my_QTextEdit::UnitTest() after QApplication is properly instantiated and event loop is running. Or, you can implement your own class inherited from QObject, create public slot, create that object prior to running app.exec() (passing to it pointer to QTextEdit if necessary) ; and connect to the slot the same way - whatever suits your needs better.
In my automated Qt tests, I generally skip the use of QApplication::exec in favour of using QCoreApplication::hasPendingEvents and QCoreApplication::processEvents - this lets you do some prep work, flush the event queue (so Qt gets a chance to actually show your window), do some more work, let Qt handle any additional events that this has thrown up, etc; it's a very handy approach for achieving the fine-grained control you need when you want to exercise small pieces of logic.
reasonably working example code for doing this is in this related question's answer: Qt event loop and unit testing?