我应该为Qt使用什么单元测试框架?

Ras*_*ber 47 qt unit-testing googletest qttest qtestlib

我刚刚开始一个需要一些跨平台GUI的新项目,我们选择了Qt作为GUI框架.

我们也需要一个单元测试框架.直到大约一年前,我们使用内部开发的C++单元测试框架 - 项目,但我们现在正在转向使用Google Test进行新项目.

有没有人有使用Google Test for Qt-applications的经验?QtTest/QTestLib是更好的选择吗?

我仍然不确定我们想在项目的非GUI部分使用Qt多少 - 我们可能更喜欢在核心代码中使用STL/Boost,并使用基于Qt的GUI的小接口.

编辑:看起来很多人都倾向于QtTest.是否有任何人有经验将其与连续集成服务器集成?此外,在我看来,必须为每个新测试用例处理单独的应用程序会导致很多摩擦.有什么好方法可以解决这个问题吗?Qt Creator是否有一个处理此类测试用例的好方法,或者您是否需要为每个测试用例创建一个项目?

Joe*_*Joe 38

您不必创建单独的测试应用程序.只需在与此类似的独立main()函数中使用qExec:

int main(int argc, char *argv[])
{
    TestClass1 test1;
    QTest::qExec(&test1, argc, argv);

    TestClass2 test2;
    QTest::qExec(&test2, argc, argv);

    // ...

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这将在一个批次中执行每个类中的所有测试方法.

您的testclass .h文件如下所示:

class TestClass1 : public QObject
{
Q_OBJECT

private slots:
    void testMethod1();
    // ...
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,这个设置在Qt文档中并没有很好地描述,即使它对许多人来说似乎非常有用.

  • 不应多次调用qExec:因为它会破坏命令行支持.使用QtTest编写测试时,可以使用`-functions`选项列出测试的所有函数,并通过在命令行上传递它来运行单个函数.如果多次调用qExec,则会中断,因为只有第一次调用才会处理命令行选项. (4认同)

SSJ*_*_GZ 20

我开始使用QtTest为我的应用程序,非常,很快就开始遇到它的限制.两个主要问题是:

1)我的测试运行得非常快 - 足够快,加载可执行文件,设置Q(核心)应用程序(如果需要)等的开销经常使测试本身的运行时间相形见绌!链接每个可执行文件也需要花费很多时间.

随着越来越多的类被添加,开销不断增加,很快就成了一个问题 - 单元测试的目标之一就是拥有一个安全网,运行速度快,根本不是负担,这是迅速变得不是这样.解决方案是将多个测试套件集成到一个可执行文件中,虽然(如上所示)这主要是可行的,但它不受支持并且具有重要的局限性.

2)没有夹具支持 - 对我来说是一个交易破坏者.

所以过了一段时间,我转而使用Google Test - 它是一个功能更强大,更复杂的单元测试框架(特别是与Google Mock一起使用时)并解决1)和2),而且,你仍然可以轻松使用方便的QTestLib功能例如QSignalSpy和GUI事件的模拟等.切换时有点痛苦,但幸好项目没有进展太远,许多变化都可以自动化.

就个人而言,我不会在未来的项目中使用QtTest而不是谷歌测试 - 如果没有提供我能看到的真正优势,并且有重要的缺点.

  • @KeyserSoze任何需要QWidgets的端到端/集成测试都有一个QApplication; 在我的RUN_ALL_TESTS()之前,在main()中创建了这个QApplication(但不是exec()'d).可以使用QMainWindow,但我主要只在端到端测试中使用它.测试本身遵循标准的Google Test方案,我通常在一个名为Xtests.cpp的文件中对X类进行所有单元测试.所以它本质上是一个标准的gtest项目,对Qt有一些让步(在以正常方式运行测试之前创建QApplication). (3认同)
  • 我不知道它是否是最近的,但 Qt 测试允许添加两个私有插槽 [init](http://doc.qt.io/qt-5/qtest-overview.html#creating-a-test) 和 [cleanup] (http://doc.qt.io/qt-5/qtest-overview.html#creating-a-test)分别在每个测试函数之前和之后调用。 (2认同)

mlv*_*ljr 19

附加到Joe的回答.

这是我使用的一个小标题(testrunner.h),包含一个产生事件循环的实用程序类(例如,需要测试排队的信号槽连接和数据库)和"运行"QTest兼容的类:

#ifndef TESTRUNNER_H
#define TESTRUNNER_H

#include <QList>
#include <QTimer>
#include <QCoreApplication>
#include <QtTest>

class TestRunner: public QObject
{
    Q_OBJECT

public:
    TestRunner()
        : m_overallResult(0)
    {}

    void addTest(QObject * test) {
        test->setParent(this);
        m_tests.append(test);
    }

    bool runTests() {
        int argc =0;
        char * argv[] = {0};
        QCoreApplication app(argc, argv);
        QTimer::singleShot(0, this, SLOT(run()) );
        app.exec();

        return m_overallResult == 0;
    }
private slots:
    void run() {
        doRunTests();
        QCoreApplication::instance()->quit();
    }
private:
    void doRunTests() {
        foreach (QObject * test, m_tests) {
            m_overallResult|= QTest::qExec(test);
        }
    }

    QList<QObject *> m_tests;
    int m_overallResult;
};

#endif // TESTRUNNER_H
Run Code Online (Sandbox Code Playgroud)

像这样使用它:

#include "testrunner.h"
#include "..." // header for your QTest compatible class here

#include <QDebug>

int main() {
    TestRunner testRunner;
    testRunner.addTest(new ...()); //your QTest compatible class here

    qDebug() << "Overall result: " << (testRunner.runTests()?"PASS":"FAIL");

    return 0;
}
Run Code Online (Sandbox Code Playgroud)


mat*_*tr- 18

我不知道QTestLib在一般术语中比另一个框架"更好".它有一件事做得很好,这提供了一种测试基于Qt的应用程序的好方法.

您可以将QTest集成到基于Google Test的新设置中.我没有尝试过,但根据QTestLib的架构,看起来它不会太复杂.

使用纯QTestLib编写的测试具有可以使用的-xml选项,以及一些XSLT转换,可转换为持续集成服务器所需的格式.但是,很多情况取决于您使用的CI服务器.我想这同样适用于GTest.

每个测试用例的单个测试应用程序从未对我造成太大的摩擦,但这取决于拥有一个构建系统,可以在管理测试用例的构建和执行方面做得不错.

我不知道Qt Creator中每个测试用例需要一个单独的项目,但是自从我上次查看Qt Creator以来它可能已经改变了.

我还建议坚持使用QtCore并远离STL.在整个过程中使用QtCore将使处理需要Qt数据类型的GUI位更容易.在这种情况下,您不必担心从一种数据类型转换为另一种数据类型.


Pat*_*ola 6

为什么不使用Qt中包含的单元测试框架?一个例子:QtTestLib教程.