Qt event loop and unit testing?

后端 未结 3 768
Happy的楠姐
Happy的楠姐 2020-12-16 11:05

I\'we started experimenting with unit testing in Qt and would like to hear comments on a scenario that involves unit testing signals and slots.

Here is an example:

3条回答
  •  北荒
    北荒 (楼主)
    2020-12-16 11:52

    Good question. Main issues I've hit are (1) needing to let app do app.exec() yet still close-at-end to not block automated builds and (2) needing to ensure pending events get processed before relying on the result of signal/slot calls.

    For (1), you could try commenting out the app.exec() in main(). BUT then if someone has FooWidget.exec() in their class that you're testing, it's going to block/hang. Something like this is handy to force qApp to exit:

    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:"< 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;
    }
    

    For (2), basically you have to coerce QApplication into finishing up the queued events if you're trying to verify things like QEvents from Mouse + Keyboard have expected outcome. This FlushEvents<>() method is helpful:

    template  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);
    } };
    

    Usage example below. "dialog" is instance of MyDialog. "baz" is instance of Baz. "dialog" has a member of type Bar. When a Bar selects a Baz, it emits a signal; "dialog" is connected to the signal and we need to make sure the associated slot has gotten the message.

    void Bar::select(Baz*  baz) {
      if( baz->isValid() ) {
         m_selected << baz;
         emit SelectedBaz();//<- dialog has slot for this
    }  }    
    
    TEST(Dialog,BarBaz) {  /**/
    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: "
            <();  // 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) );
    /**/
    }
    

提交回复
热议问题