12

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

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

我想为模块编写测试。模块只提供一个类供模块用户使用,但是在其他类中抽象了很多逻辑,除了测试公共类之外,我也想测试一下。

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

QTEST_MAIN(TestClass)
#include "test_class.moc"

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

当然,可以看一下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);
}
4

4 回答 4

6

与@cjhuit 发布的答案相关

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

我尽量避免这样的事情:

MyTestClass1 t1;   t1.run();
MyTestClass2 t2;   t2.run();
//etc...

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

这是我的做法:

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

qtestsuite.cpp

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

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

QTestSuite::QTestSuite() : QObject()
{
    m_suites.push_back(this);
}

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;
}

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"

另外,创建 .pro 文件

qmake -project "CONFIG += qtestlib"
于 2014-06-29T13:44:35.823 回答
5

在我们使用 QTest 的设置中,我们做了一些事情让它变得更好。

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

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

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

于 2010-05-03T18:15:23.073 回答
4

是的,QTest 强制测试结构有点奇怪,并且通常不如 Google 测试/模拟框架。对于一个项目,我被迫使用 QTest(客户要求),这是我使用它的方式:

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

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

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

于 2010-05-02T18:50:28.210 回答
0

通常我组织测试,每个测试类都有一个测试可执行文件。

最终一个测试程序只能测试一个测试类。

这是一件好事。它将您的测试彼此隔离,防止像一个测试中的崩溃这样的事情阻塞您的所有其他测试。该崩溃可能是由几个正在测试的类中的公共组件引起的。然后,失败的模式会让您了解问题的根本根源。基本上,如果您的测试彼此独立,您将获得更好的故障诊断信息。

轻松设置多个可执行文件并分别运行每个测试。使用测试运行器生成所有测试过程。

更新:

我对此有所改变。一旦你有一个包含大量测试的大程序,链接数百个测试可执行文件就会变得非常慢。我的新偏好是将库的所有测试放入可执行文件中,并使用传递给测试可执行文件的命令行参数选择要调用的测试。

这将可执行文件的数量从数百个减少到数十个,但保留了单独运行测试的优势。

于 2011-03-04T22:32:49.010 回答