题
我开始使用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);
}
解决方案
是的,QTest强制有点奇怪的测试结构,通常不如Google测试/模拟框架。对于一个项目,我被迫使用QTest(客户需求),这就是我的使用方式:
- 我将所有测试一起编译为一个子dir模板项目
- 为了使创建新测试更容易,我通过使用COMMON.PRI文件共享许多项目配置。
- 如果可能的话,我共享对象文件目录以加快汇编
- 我使用批处理+awk+sed脚本运行它们。
设置这四个点非常容易,使QTest几乎令人愉快。您在运行上述配置未解决的多个测试方面有一些问题吗?
PS:运行测试以您的操作方式,即调用多个QTest :: QEXEC会导致-O命令行开关问题 - 您将仅获得最后一个测试类的结果。
其他提示
与@cjhuitt发布的答案有关
这是一个示例,可以消除手动调用每个测试对象的需要
我试图避免这样的事情:
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"
在与Qtest的设置中,我们做了一些事情来使其变得更好。
- 定义一个子类的子类,该子类用作任何新单元测试类的基类。
- 在该类的构造函数中,我们将测试的实例添加到测试的静态列表中,在驱动器中,我们将其删除。
- 然后,我们具有静态功能,可以通过测试循环并使用它们运行
QTest::qExec()
. 。 (我们每次累积返回的值,并从我们的函数中返回。) main()
调用此功能,并将结果返回为成功/失败。- 最后,在特定测试本身的汇编单元中,我们通常包括该类别的静态实例。
此设置意味着课程将在之前实例化 main()
运行,因此将其添加到主要运行时测试的类列表中。该框架要求您只需要正确继承您的课程,如果您始终希望它运行,则需要实例化静态实例。
我们偶尔还会创建其他可选测试,这些测试是根据命令行开关添加的。
通常,我会通过每类测试进行一个测试,以一项测试进行测试。
最终,一个测试程序能够仅测试一个测试类。
这是一件好事。它彼此隔离您的测试,防止像一次测试中的崩溃之类的事情阻止所有其他测试。这种崩溃可能是由正在测试的几个类中的一个共同组件引起的。然后,失败的模式将使您转向问题的基本起源。基本上,如果您的测试彼此独立,则可以更好地诊断出失败的信息。
使设置多个可执行文件并分别运行每个测试。使用测试跑者催生所有测试过程。
更新:
我对此有所改变。一旦您拥有大量测试的大程序,链接数百个测试可执行文件就会变得非常慢。我的新偏爱是将库的所有测试都放入可执行文件中,并选择使用传递给测试可执行文件的命令行参数调用的测试。
这将可执行文件的数量从数百到数十个减少,但保留了分别运行测试的优势。