The*_*eer 23 qt unit-testing qt4 event-handling event-loop
我开始尝试在Qt中进行单元测试,并希望听到有关涉及单元测试信号和插槽的场景的评论.
这是一个例子:
我想测试的代码是(m_socket是指向QTcpSocket
):
void CommunicationProtocol::connectToCamera()
{
m_socket->connectToHost(m_cameraIp,m_port);
}
Run Code Online (Sandbox Code Playgroud)
由于这是一个异步调用,我无法测试返回的值.但是,我想测试套接字在成功的connection(void connected ()
)上发出的响应信号是否实际发出.
我在下面写了测试:
void CommunicationProtocolTest::testConnectToCammera()
{
QSignalSpy spy(communicationProtocol->m_socket, SIGNAL(connected()));
communicationProtocol->connectToCamera();
QTest::qWait(250);
QCOMPARE(spy.count(), 1);
}
Run Code Online (Sandbox Code Playgroud)
我的动机是,如果响应不会在250毫秒内发生,那就是错误的.
然而,信号永远不会被捕获,我无法确定它是否发射.但我注意到我没有在测试项目的任何地方启动事件循环.在开发项目中,事件循环以main开头QCoreApplication::exec()
.
总结一下,当单元测试一个依赖于信号和插槽的类时,应该在哪里
QCoreApplication a(argc, argv);
return a.exec();
Run Code Online (Sandbox Code Playgroud)
在测试环境中运行?
Dan*_*gan 10
我意识到这是一个老线程,但是当我点击它和其他人的时候,没有答案,彼得和其他评论的答案仍然没有使用QSignalSpy.
为了回答你关于"需要QCoreApplication exec功能的地方"的原始问题,基本上答案是,它不是.QTest和QSignalSpy已经内置了.
您在测试用例中真正需要做的是"运行"现有的事件循环.
假设您使用的是Qt 5:http: //doc.qt.io/qt-5/qsignalspy.html#wait
所以要修改你的例子以使用wait函数:
void CommunicationProtocolTest::testConnectToCammera()
{
QSignalSpy spy(communicationProtocol->m_socket, SIGNAL(connected()));
communicationProtocol->connectToCamera();
// wait returns true if 1 or more signals was emitted
QCOMPARE(spy.wait(250), true);
// You can be pedantic here and double check if you want
QCOMPARE(spy.count(), 1);
}
Run Code Online (Sandbox Code Playgroud)
这应该给你所需的行为,而不必创建另一个事件循环.
好问题.我遇到的主要问题是(1)需要让应用程序执行app.exec()但仍然关闭以阻止自动构建和(2)需要确保在依赖信号结果之前处理待处理事件/ slot调用.
对于(1),您可以尝试在main()中注释掉app.exec().但是,如果有人在他们正在测试的类中有FooWidget.exec(),那么它将阻止/挂起.像这样的东西迫使qApp退出:
int main(int argc, char *argv[]) {
QApplication a( argc, argv );
//prevent hanging if QMenu.exec() got called
smersh().KillAppAfterTimeout(300);
::testing::InitGoogleTest(&argc, argv);
int iReturn = RUN_ALL_TESTS();
qDebug()<<"rcode:"<<iReturn;
smersh().KillAppAfterTimeout(1);
return a.exec();
}
struct smersh {
bool KillAppAfterTimeout(int secs=10) const;
};
bool smersh::KillAppAfterTimeout(int secs) const {
QScopedPointer<QTimer> timer(new QTimer);
timer->setSingleShot(true);
bool ok = timer->connect(timer.data(),SIGNAL(timeout()),qApp,SLOT(quit()),Qt::QueuedConnection);
timer->start(secs * 1000); // N seconds timeout
timer.take()->setParent(qApp);
return ok;
}
Run Code Online (Sandbox Code Playgroud)
对于(2),如果你试图验证像QEvent
鼠标+键盘这样的东西有预期的结果,你基本上必须强制QApplication完成排队的事件.这种FlushEvents<>()
方法很有帮助:
template <class T=void> struct FlushEvents {
FlushEvents() {
int n = 0;
while(++n<20 && qApp->hasPendingEvents() ) {
QApplication::sendPostedEvents();
QApplication::processEvents(QEventLoop::AllEvents);
YourThread::microsec_wait(100);
}
YourThread::microsec_wait(1*1000);
} };
Run Code Online (Sandbox Code Playgroud)
下面的用法示例."对话框"是MyDialog的实例."巴兹"是巴兹的例子."dialog"具有Bar类型的成员.当Bar选择Baz时,它会发出一个信号; "dialog"连接到信号,我们需要确保相关的插槽已经获得了消息.
void Bar::select(Baz* baz) {
if( baz->isValid() ) {
m_selected << baz;
emit SelectedBaz();//<- dialog has slot for this
} }
TEST(Dialog,BarBaz) { /*<code>*/
dialog->setGeometry(1,320,400,300);
dialog->repaint();
FlushEvents<>(); // see it on screen (for debugging)
//set state of dialog that has a stacked widget
dialog->setCurrentPage(i);
qDebug()<<"on page: "
<<i; // (we don't see it yet)
FlushEvents<>(); // Now dialog is drawn on page i
dialog->GetBar()->select(baz);
FlushEvents<>(); // *** without this, the next test
// can fail sporadically.
EXPECT_TRUE( dialog->getSelected_Baz_instances()
.contains(baz) );
/*<code>*/
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
7855 次 |
最近记录: |