使用Qt的QTestLib模块进行测试

ak.*_*ak. 12 qt unit-testing qttest

我开始用Qt的单元测试系统编写一些测试.

你通常如何组织测试?它是每个模块类的一个测试类,还是用单个测试类测试整个模块?Qt文档建议遵循前一策略.

我想为模块编写测试.该模块只提供了一个将由模块用户使用的类,但是除了测试公共类之外,还有很多其他类中抽象的逻辑,我也想测试它们.

问题是Qt提出的运行测试的方法涉及到QTEST_MAIN宏:

QTEST_MAIN(TestClass)
#include "test_class.moc"
Run Code Online (Sandbox Code Playgroud)

最终,一个测试程序只能测试一个测试类.为模块中的每个类创建测试项目有点糟糕.

当然,人们可以看看QTEST_MAIN宏,重写它,并运行其他测试类.但有什么东西可以开箱即用吗?

到目前为止,我手工完成:

#include "one.h"
#include "two.h"

int main(int argc, char *argv[]) 
{ 
    QCoreApplication app(argc, argv); 
    TestOne one;
    QTest::qExec(&one, argc, argv);
    TestOne two;
    QTest::qExec(&two, argc, argv);
}
Run Code Online (Sandbox Code Playgroud)

foo*_*olo 6

与@cjhuitt发布的答案相关

这是一个不需要手动调用每个测试对象的示例

我试着避免这样的事情:

MyTestClass1 t1;   t1.run();
MyTestClass2 t2;   t2.run();
//etc...
Run Code Online (Sandbox Code Playgroud)

我的解决方案是让测试对象继承自基类,将其自身添加到静态列表中 .然后主程序执行该列表中的所有测试对象.这样,不需要更改任何支持框架代码.唯一改变的是测试类本身.

我是这样做的:

qtestsuite.h - 测试对象的基类

#ifndef QTESTSUITE_H
#define QTESTSUITE_H

#include <QObject>
#include <vector>

class QTestSuite : public QObject
{
    Q_OBJECT
public:
    static std::vector<QObject*> m_suites;

public:
    explicit QTestSuite();

};

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

qtestsuite.cpp

#include "qtestsuite.h"
#include <iostream>

std::vector<QObject*> QTestSuite::m_suites;

QTestSuite::QTestSuite() : QObject()
{
    m_suites.push_back(this);
}
Run Code Online (Sandbox Code Playgroud)

testall.cpp - 运行测试

#include "qtestsuite.h"

#include <QtTest/QtTest>
#include <iostream>

int main(int, char**)
{
    int failedSuitesCount = 0;
    std::vector<QObject*>::iterator iSuite;
    for (iSuite = QTestSuite::m_suites.begin(); iSuite != QTestSuite::m_suites.end(); iSuite++)
    {
        int result = QTest::qExec(*iSuite);
        if (result != 0)
        {
            failedSuitesCount++;
        }
    }
    return failedSuitesCount;
}
Run Code Online (Sandbox Code Playgroud)

mytestsuite1.cpp - 一个示例测试对象,创建更多这些

#include "qtestsuite.h"

#include <QtTest/QtTest>

class MyTestSuite1: public QTestSuite
{
     Q_OBJECT
private slots:
    void aTestFunction();
    void anotherTestFunction();
};

void MyTestSuite1::aTestFunction()
{
    QString str = "Hello";
    QVERIFY(str.toUpper() == "this will fail");
}

void MyTestSuite1::anotherTestFunction()
{
    QString str = "Goodbye";
    QVERIFY(str.toUpper() == "GOODBYE");
}

static MyTestSuite1 instance;  //This is where this particular test is instantiated, and thus added to the static list of test suites

#include "mytestsuite1.moc"
Run Code Online (Sandbox Code Playgroud)

另外,要创建.pro文件

qmake -project "CONFIG += qtestlib"
Run Code Online (Sandbox Code Playgroud)

  • 我现在将这种方法用于几个测试项目两年,但现在我遇到了以下静态初始化顺序问题:`static MyTestSuite1 instance`可以在`m_suites`之前初始化.因此,最好让m_suites成为一个返回对静态成员的引用的函数:`std :: vector <QObject*>&QTestSuite :: mSuites(){static std :: vector <QObject*> INST; 返回INST;}` (3认同)

Cal*_*itt 5

在我们使用QTest的设置中,我们做了一些事情来使它更好.

  • 定义QObject的子类,用作任何新单元测试类的基类.
  • 在该类的构造函数中,我们将测试实例添加到静态测试列表中,并在析构函数中将其删除.
  • 然后我们有一个静态函数循环遍历测试并使用它们运行它们QTest::qExec().(我们累积每次返回的值,并从我们的函数返回.)
  • main() 调用此函数,并将结果作为成功/失败返回.
  • 最后,在特定测试本身的编译单元中,我们通常包含该类的静态实例.

此设置意味着该类将在main()运行之前进行实例化,因此它将被添加到类列表中以在主运行时进行测试.该框架要求您只需要正确地继承您的类,并在您始终希望它运行时实例化静态实例.

我们偶尔也会创建其他可选测试,这些测试是基于命令行开关添加的.

  • 嗨迦勒,还在挣扎着.您是否愿意分享任何示例代码?谢谢. (2认同)

cha*_*lup 4

是的,QTest 强制执行有点奇怪的测试结构,并且通常不如 Google Test/Mock Framework。对于一个项目,我被迫使用 QTest(客户要求),以下是我如何使用它:

  1. 我将所有测试一起编译为子目录模板项目
  2. 为了使创建新测试更容易,我通过使用每个测试 .pro 文件中包含的 common.pri 文件来共享许多项目配置
  3. 如果可能的话我共享目标文件目录以加快编译速度
  4. 我使用batch+awk+sed 脚本运行它们。

设置这四点非常简单,并且使 QTest 的使用几乎令人愉快。您在运行多个测试时是否遇到上述配置无法解决的问题?

PS:按照您的方式运行测试,即调用多个 QTest::qExec 会导致 -o 命令行开关出现问题 - 您将仅获得最后一个测试类的结果。