Qt Auto-UI 测试因消息框而停止.如何在消息框上模拟输入?

我的任务是为正在开发的软件编写自动化 UI 测试.碰巧的是,有单选按钮触发了一个消息框,这会停止我的自动化测试,直到我手动确认它(按 ENTER).问题是我不知道如何调用新召唤的消息框,然后通过 QTest::keyClick(<object>, QtKey::Key_Enter); 确认它并进行自动测试继续运行.

My task is to write an automated UI test for a software being developed. It happens so, that there are radiobuttons triggering a messagebox, which stops my automated test until I manually confirm it (pressing ENTER). The issue is that I do not know how I can call that newly summoned messagebox and then have it confirmed by QTest::keyClick(<object>, QtKey::Key_Enter); and have my automated test continue the run.

我正在使用 QWidgets、QApplication、Q_OBJECT 和 QtTest.我将提供与我正在使用的代码类似的代码:

I am using QWidgets, QApplication, Q_OBJECT and QtTest. I will provide a code similar to what I am working with:

void testui1(){
Form1* myform = new Form1();
myform->show();
QTest::mouseClick(myform->radioButton01, Qt::LeftButton, Qt::NoModifier, QPoint(), 100);
// Message box pops up and stops the operation until confirmed
QTest::mouseClick(myform->radioButton02, Qt::LeftButton, Qt::NoModifier, QPoint(), 100);
// again
...
}

我如何编写脚本来自动确认消息框?消息框只是一个 [OK] 类型,所以我不需要它来返回我是否按下了是或否.一个 QTest::keyClick(, Qt::Key_Enter) 方法需要知道它应该按回车键到哪个对象.我尝试将 myform 包含到对象中,但它不起作用.谷歌搜索我没有找到答案.我发现以下结果不适用于我正在寻找的内容

How exactly can I script to confirm the message box automatically? The message box is only an [OK] type, so I don't need it to return whether I have pressed Yes or No. A QTest::keyClick(<target object>, Qt::Key_Enter) method needs to know to which object it should press enter to. I tried including myform into the object and it did not work. Googling I did not find the answer. I found the following result as not functioning for what I am looking for

QWidgetList allToplevelWidgets = QApplication::topLevelWidgets();
foreach (QWidget *w, allToplevelWidgets) {
    if (w->inherits("QMessageBox")) {
        QMessageBox *mb = qobject_cast<QMessageBox *>(w);
        QTest::keyClick(mb, Qt::Key_Enter);
    }
}

推荐答案

问题是,一旦你点击"了你的单选按钮,导致 QMessageBox::exec 被调用,在用户单击按钮之前,您的代码将停止运行.

The problem is that once you've "clicked" on your radio button, which results in QMessageBox::exec being called, your code stops running until the user clicks on of the buttons.

您可以通过在单击单选按钮之前启动计时器来模拟用户单击按钮.

You can simulate the user clicking a button by starting a timer before you click on the radio button.

在定时器的回调函数中你可以使用QApplication::activeModalWidget() 获取消息框的指针,然后调用close就可以了.

In the callback function for the timer you can use QApplication::activeModalWidget() to obtain a pointer to the message box, and then just call close on it.

QTimer::singleShot(0, [=]()
    {
        QWidget* widget = QApplication::activeModalWidget();
        if (widget)
            widget->close();
    });

如果你想按下消息框上的特定键,你可以使用 QCoreApplication::postEvent 将按键事件发布到消息框

If you want to press a specific key on the message box, you can use QCoreApplication::postEvent to post a key event to the message box

QTimer::singleShot(0, [=]()
    {
        int key = Qt::Key_Enter; // or whatever key you want

        QWidget* widget = QApplication::activeModalWidget();
        if (widget)
        {
            QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier); 
            QCoreApplication::postEvent(widget, event);
        }
    });

因此,就这与您提供的示例代码的关系而言:

So in terms of how this ties into the sample code you gave:

void testui1()
{
    Form1* myform = new Form1();
    myform->show();

    QTimer::singleShot(0, [=]()
        {
            QWidget* widget = QApplication::activeModalWidget();
            if (widget)
                widget->close();
            else
                QFAIL("no modal widget");
        });

    QTest::mouseClick(myform->radioButton01, Qt::LeftButton, Qt::NoModifier, QPoint(), 100);
}

将以上所有内容组合在一起的示例应用:

#include <QApplication>
#include <QMainWindow>
#include <QHBoxLayout>
#include <QPushButton>
#include <QTimer>
#include <QMessageBox>
#include <iostream>

int main(int argc, char** argv)
{
    QApplication app(argc, argv);
    QMainWindow window;

    QWidget widget;
    window.setCentralWidget(&widget);

    QHBoxLayout layout(&widget);

    QPushButton btn("go");
    layout.addWidget(&btn);

    QObject::connect(&btn, &QPushButton::clicked, [&]()
        {
            QTimer::singleShot(0, [=]()
                {
                    QWidget* widget = QApplication::activeModalWidget();
                    if (widget)
                    {
                        widget->close();
                    }
                    else
                    {
                        std::cout << "no active modal
";
                    }
                });

            QMessageBox(
                QMessageBox::Icon::Warning,
                "Are you sure?",
                "Are you sure?",
                QMessageBox::Yes | QMessageBox::No,
                &window).exec();
        });

    window.show();
    return app.exec();
}

点击 Go 看起来就像什么都没有发生,因为 QMessageBox 立即关闭.

要证明消息框已显示然后关闭,您可以将调用 QTimer::singleShot 的时间增加到一个值,例如 1000.现在它会显示消息框 1 秒,然后它会被计时器关闭.

To prove that the message box is shown and then closed you can increase the time in the call to QTimer::singleShot to a value such as 1000. Now it will show the message box for 1 second, and then it will be closed by the timer.

相关文章