如何防止qFatal()中止应用程序?

时间:2010-04-30 18:55:05

标签: unit-testing qt googletest

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

  

使用。调用消息处理程序   致命的消息如果没有消息   处理程序已安装,   消息打印到stderr。下   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()”,   file myclass.cpp,第21行程序   意外地完成了。

即使断言失败,我还能做什么让我的测试继续运行?

4 个答案:

答案 0 :(得分:4)

在进行发布构建时,

Q_ASSERT_X无法编译。

因此,对于单元测试,请执行发布版本,它不会调用qFatal。

答案 1 :(得分:2)

-DqFatal = qCritical:)

答案 2 :(得分:1)

至少对于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并且应该让您大致了解发生了什么。

答案 3 :(得分:0)

在某些情况下,您可能无法抑制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() );

并不是说这是一种不错的方法,只是试图证明可以为这个问题做些什么。

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