【问题标题】:How do I prevent qFatal() from aborting the application?如何防止 qFatal() 中止应用程序?
【发布时间】:2010-04-30 18:55:05
【问题描述】:

我的 Qt 应用程序使用 Q_ASSERT_X,它调用 qFatal(),它(默认情况下)中止应用程序。这对应用程序来说很好,但我想在对应用程序进行单元测试时抑制这种行为。 (我正在使用Google Test Framework。)我在一个单独的项目中进行单元测试,静态链接到我正在测试的类。 qFatal() 的documentation 内容如下:

调用消息处理程序 致命消息消息。如果没有消息 处理程序已安装, 消息被打印到标准错误。在下面 Windows,消息被发送到 调试器。

如果您使用的是默认消息 处理程序此函数将中止 Unix 系统创建核心转储。在 Windows,对于调试版本,这个 函数将报告 _CRT_ERROR 使您能够将调试器连接到 应用程序。

...

为了在运行时抑制输出, 安装您自己的消息处理程序 qInstallMsgHandler()。

这是我的 main.cpp 文件:

#include <gtest/gtest.h>
#include <QApplication>

void testMessageOutput(QtMsgType type, const char *msg) {
    switch (type) {
    case QtDebugMsg:
        fprintf(stderr, "Debug: %s\n", msg);
        break;
    case QtWarningMsg:
        fprintf(stderr, "Warning: %s\n", msg);
        break;
    case QtCriticalMsg:
        fprintf(stderr, "Critical: %s\n", msg);
        break;
    case QtFatalMsg:
        fprintf(stderr, "My Fatal: %s\n", msg);
        break;
    }
}

int main(int argc, char **argv)
{
    qInstallMsgHandler(testMessageOutput);
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

但我的应用程序仍在断言处停止。我可以看出我的自定义处理程序正在被调用,因为运行我的测试时的输出是:

我的致命:ASSERT 失败 MyClass::doSomething: "doSomething()", 文件 myclass.cpp,第 21 行程序 意外结束了。

我该怎么做才能让我的测试在断言失败时继续运行?

【问题讨论】:

    标签: unit-testing qt googletest


    【解决方案1】:

    Q_ASSERT_X 在发布版本时编译为空。

    因此,对于单元测试,进行发布构建,它不会调用 qFatal。

    【讨论】:

      【解决方案2】:

      -DqFatal=qCritical :)

      【讨论】:

        【解决方案3】:

        至少对于 Qt-4.6.2,你无能为力。

        src/corelib/global/qglobal.cpp 定义void qt_message_output(QtMsgType msgType, const char *buf),它首先检查是否已安装处理程序。如果是这样,它会调用它,否则它使用默认处理程序。紧接着,它几乎总是中止(Unix/MingWn)或调用 exit(其他)。

        我在网上找不到当前源代码的浏览器,但the Qt-4.2.2 source code is mostly identical 应该可以让您大致了解发生了什么。

        【讨论】:

        • 谢谢,卡莱布。臭死了。有点苛刻,但我想我会使用预处理器从调试版本中排除“预期失败”测试,并且只针对发布版本进行测试。
        • 感谢@Adam - 我检查了 github,但在那里找不到它,而且 Google 没有在搜索结果中合理地列出它。
        【解决方案4】:

        在某些情况下,您可能无法抑制 qFatal 并静默继续,测试的组件可能处于这样的状态,即在几行之后无论如何都会发生崩溃。避免这种情况的一种方法是在您的测试代码中的某处存根 qFatal ;)

        void qFatal(const char *msg, ...)
        {
            QT_THROW(std::some_exception);
        }
        

        然后你可以有一些自己的断言宏:

        #define CUSTOM_QEXPECT_FAIL( method ) { bool failed = false;\
            try { \
                method ; \
            }\
            catch(...) { \
                failed = true; \
            } \
            QVERIFY(failed); }
        

        并在您的代码中使用它,例如:

        CUSTOM_QEXPECT_FAIL( testedObj->panicAtTheDisco() );
        

        并不是说这在任何方面都是好的方法,只是试图证明可以为这个问题做点什么。

        另外,我没有仔细阅读,您正在静态链接测试类。存根在这种情况下可能不起作用,除非您将其构建到您的测试可执行文件中。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-08-29
          • 1970-01-01
          • 1970-01-01
          • 2011-11-24
          • 2015-07-01
          • 2018-11-11
          相关资源
          最近更新 更多