很好的问题。我遇到的主要问题是(1)需要让应用程序执行app.exec(),但仍然需要在结束时关闭以不阻塞自动构建,以及(2)需要确保待处理事件在依赖于信号/插槽调用结果之前得到处理。
对于(1),您可以尝试在main()中注释掉app.exec()。
但是如果您正在测试的类中有FooWidget.exec(),那么它将会被阻塞/挂起。以下代码可强制qApp退出:
int main(int argc, char *argv[]) {
QApplication a( argc, argv );
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);
timer.take()->setParent(qApp);
return ok;
}
对于(2),如果你想要验证鼠标和键盘等输入事件的预期结果,基本上你需要强制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);
} };
以下是使用示例。
“dialog”是MyDialog的实例。
“baz”是Baz的实例。
“dialog”有一个Bar类型的成员。
当Bar选择Baz时,它会发出信号;
“dialog”连接到信号,并且我们需要确保相关的插槽已经收到了消息。
void Bar::select(Baz* baz) {
if( baz->isValid() ) {
m_selected << baz;
emit SelectedBaz();
} }
TEST(Dialog,BarBaz) {
dialog->setGeometry(1,320,400,300);
dialog->repaint();
FlushEvents<>();
dialog->setCurrentPage(i);
qDebug()<<"on page: "
<<i;
FlushEvents<>();
dialog->GetBar()->select(baz);
FlushEvents<>();
EXPECT_TRUE( dialog->getSelected_Baz_instances()
.contains(baz) );
}
QTEST_MAIN(CommunicationProtocolTest)
宏。 - vahanchoqWait
会自旋一条事件循环,所以这不是问题。尝试使用更长的超时时间。最理想的情况是,您可以提供自己的QAbstractSocket
模拟实现,用于测试。 - Kuba hasn't forgotten Monica