1

I have looked at the 5 Qt testing examples including the one about GUI events, but these examples are way too simple.

I want to test my program by launching it, simulating some clicks, and checking the value of instance variables that have been changed by those clicks.

I assume that this test below is illogical: a.exec() blocks the thread until the program is closed, and when the program is closed w has been deleted I think (or will be deleted later?).

So how to write system/GUI tests?

My test:

void LaunchProgramTest::LaunchProgramTestFunction() {
    QApplication a(argc, argv);
    MainWindow *w = new MainWindow();

    w->show();

    a.exec();

    int testResult = w->myTestFunction();

    qDebug() << testResult; //Prints big numbers like "-17891602" or "1753770528" as if testResult was not initialized

    QVERIFY2(testResult == 3, "Incorrectly changed");
}

In mainWindow.h I declared a variable:

int testValue;

Mainwindow.cpp is the class for the main GUI of the program. In the constructor I added

testValue = 2;

Then in a function that is executed upon events I wrote

void MainWindow::on_actionTest_clicked() {
    testValue = 3;
}
The Coding Wombat
  • 805
  • 1
  • 10
  • 29

1 Answers1

1

enter code hereSo)) you need to add QTest, add .pro

QT  += testlib

and

#include <QTest>

I will show an example of my implementation for MousePress, the rest you can do yourself))

struct EventMK
    {
        int type;
        QString m_widPath;
        int _timer;
        int width;
        int height;
        QPoint p;
        QPoint g;
        int button;
        int buttons;
        int modifiers;
        int _key;
        QString text;
        void print(){
            qDebug()<<"{ \n"
               <<"type "<< type<<","<<"\n"
               <<"Widget_Path "<< m_widPath<<","<<"\n"
               <<"Timer "<< _timer<<","<<"\n"
               <<"Width "<< width<<","<<"\n"
               <<"Height "<< height<<","<<"\n"
               <<"Pos_x "<< p.x()<<","<<"\n"
               <<"Pos_y "<< p.y()<<","<<"\n"
               <<"Global_x "<< g.x()<<","<<"\n"
               <<"Global_y "<< g.y()<<","<<"\n"
               <<"Button "<< button<<","<<"\n"
               <<"Buttons "<< buttons<<","<<"\n"
               <<"Modifiers "<< modifiers<<","<<"\n"
               <<"Key "<< _key<<","<<"\n"
               <<"Text "<< text<<"\n"
               <<"}\n";

        }
    };

QWidget * _getWidget(EventMK ev)
{
    QString wname = ev.m_widPath;
    QStringList wpath = wname.split ( "/" );
    return QWidgetUtils::getAWidget(&wpath);
}

void _postExecution(EventMK ev, QWidget *widget)
{
    if (widget){

        //set focus
        QWidgetUtils::setFocusOnWidget(widget);

        //end simulation
        widget->setUpdatesEnabled ( true );
        widget->update();
    }
}


QPoint adaptedPosition(EventMK ev, QWidget *w)
{
    if (w == nullptr)
        return QPoint(ev.p.x(), ev.p.y());

    int orig_w = ev.width;
    int orig_h = ev.height;
    int curr_w = w->width();
    int curr_h = w->height();

    int new_x = ev.p.x() * curr_w / orig_w;
    int new_y = ev.p.y() * curr_h / orig_h;

    return QPoint(new_x, new_y);
}

and function implementation

void executeMousePressEvent(EventMK ev)
{
    QWidget* widget = _getWidget(ev);
    if ( widget == nullptr )
    {
        qDebug()<<"error: "<<__LINE__<<__FUNCTION__;
        return;  
    }

   // _preExecutionWithMouseMove(ev, widget);
    if (widget){
        QTest::mousePress ( widget, (Qt::MouseButton)ev.button , 
                                    (Qt::KeyboardModifier) ev.modifiers, 
                                     adaptedPosition(ev,widget));

    }

    _postExecution(ev, widget);
}

now left to fill struct EventMK , you need to populate it from MouseButtonPress events. Here is my example

 bool eventFilter(QObject *obj, QEvent *event)
    {
        ///
        /// process control
        ///

        //window events
        if (event->type() == QEvent::KeyPress)
        {
            handleKeyPressEvent(obj, event);
        }
        //mouse events
        else if (event->type() == QEvent::MouseButtonPress)
        {
            handleMousePressEvent(obj, event);
        }
        else if (event->type() == QEvent::MouseButtonRelease)
        {
            handleMouseReleaseEvent(obj, event);
        }
        else if (event->type() == QEvent::MouseButtonDblClick)
        {
            handleMouseDoubleEvent(obj, event);
        }
        else if (event->type() == QEvent::Wheel)
        {
            handleWheelEvent(obj, event);
        }
        //keyboard events
        else if (event->type() == QEvent::Close)
        {
            handleCloseEvent(obj, event);
        }

        ///the event should continue to reach its goal...
        return false;
    }

and

void handleMousePressEvent(QObject *obj, QEvent *event)
  {
        QWidget *widget = isValidWidget(obj);
        if (!widget){
            return;
        }        
        QMouseEvent *me = dynamic_cast< QMouseEvent*> ( event );
        //create the event
        if (widget != nullptr){
            EventMK evkm;

            evkm.type = QOE_MOUSE_PRESS;    // set your type
            evkm._timer = _timer.restart(); // add your QElapsedTimer
            evkm.m_widPath = QWidgetUtils::getWidgetPath(widget);
            evkm. width  = widget->width();
            evkm. height = widget->height();

            QPoint p ( me->pos() );
            QPoint g = widget->mapToGlobal ( p );
            evkm. p  = p;
            evkm. g = g;

            evkm. button  = me->button();
            evkm. buttons = me->buttons();
            evkm. modifiers = me->modifiers();

            evkm.print();
        }
        //send event if EventMK is valid

    }

so, it turns out we can write a scenario and run what you wanted, thanks

Vahagn Avagyan
  • 750
  • 4
  • 16