我刚刚起步,需要一些跨平台的GUI一个新的项目,我们选择的Qt的图形用户界面的框架。
我们需要一个单元测试框架,太。 直到大约一年前,我们使用C ++的内部开发的单元测试框架 - 项目,但现在我们正在过渡到使用谷歌测试新项目。
有没有人有使用谷歌试验Qt的应用程序的经验吗? 是QtTest / QTestLib一个更好的选择?
我仍然不知道我们多么希望在该项目的非GUI部分使用Qt - 我们可能宁愿只使用STL /升压核心代码的小接口的基于Qt的图形用户界面。
编辑:它看起来像许多人都对QtTest倾斜。 是否有任何人谁拥有了持续集成服务器集成这方面的经验? 此外,它似乎对我来说,必须处理每一个新的测试用例一个单独的应用程序会导致大量的摩擦。 有没有解决任何好办法吗? 难道Qt Creator中有处理此类测试用例的好办法,或者你需要对每个测试案例的一个项目?
Answer 1:
我不知道QTestLib比一个框架,另一个在这样的笼统“更好”。 有一两件事,它做得很好,这是提供给测试基于Qt应用程序的好方法。
你可以QTEST融入新的谷歌测试基础设置。 我还没有尝试过,但基于QTestLib是如何架构,现在看来似乎不会太复杂。
纯QTestLib笔试有,你可以使用,一些XSLT转换以及转换为所需要的格式为持续集成服务器的-xml选项。 然而,很多依赖于你去与CI服务器。 我会想象这同样适用于GTEST。
每个测试情况下,单一的测试应用从未引起了很多摩擦,对我来说这取决于有一个构建系统,会做管理的测试用例的建设和执行一份体面的工作。
我不知道的Qt Creator中任何可能要求每个测试用例一个单独的项目,但自从上次我看了看Qt Creator中它可能已经改变。
我也建议用QtCore坚持和保持与STL之遥。 使用QtCore整个将使处理需要Qt的数据类型更容易的GUI位。 你会不会担心在这种情况下,从一种数据类型转换为另一种。
Answer 2:
您不必创建单独的测试应用程序。 只需使用qExec与此类似一个独立的main()函数:
int main(int argc, char *argv[])
{
TestClass1 test1;
QTest::qExec(&test1, argc, argv);
TestClass2 test2;
QTest::qExec(&test2, argc, argv);
// ...
return 0;
}
这将执行在一个批次中的每个类中的所有测试方法。
你的TestClass .h文件将如下所示:
class TestClass1 : public QObject
{
Q_OBJECT
private slots:
void testMethod1();
// ...
}
不幸的是这种设置是不是真的Qt文档中描述的很好,即使它似乎是很多人非常有用。
Answer 3:
要追加到乔的回答。
这里的一个小头我使用(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
使用这样的:
#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;
}
Answer 4:
我开始使用QtTest我的应用程序,非常,非常迅速地开始运行与它的局限性。 这两个主要问题是:
1)我的测试运行速度非常快 - 快速充分地在加载的可执行文件,建立一个Q(核心)应用程序(如果需要)等的开销往往相形见绌测试本身的运行时间! 链接每个可执行文件占用了大量的时间,太。
开销只是不停的加入越来越多类增加,并很快成为了一个问题 - 的单元测试的目标之一是有运行如此之快,是不是负担,在所有的安全网,这是迅速成为并非如此。 解决的办法是多glob的测试套件为一个可执行文件,而(如上图所示),这是主要是做,能,它不支持 ,具有重要的局限性。
2)无固定支持 - 一个交易断路器我。
因此,一段时间后,我跳槽到谷歌测试 - 这是(与谷歌模拟使用时尤为突出),解决1)远远更多的其他功能和成熟的单元测试框架和2),而且,你仍然可以轻松地使用得心应手QTestLib功能如QSignalSpy和GUI事件的模拟等,这是一个痛苦位的切换,但幸运的是,该项目已不太远先进和许多的变化可以自动化。
就个人而言,我不会使用QtTest在谷歌测试为将来的项目 - 如果没有提供真正的优势,我可以看到,具有重要的缺点。
Answer 5:
为什么不使用包含在Qt的单元测试框架? 举个例子: QtTestLib教程 。
Answer 6:
我单位测试使用GTEST和我们的图书馆QSignalSpy 。 使用QSignalSpy捕获的信号。 您可以直接(如普通的方法)调用插槽对其进行测试。
Answer 7:
QtTest是用于测试所需要的Qt的事件循环/信号调度部件大多是有用的。 它的设计,每个测试用例需要一个单独的可执行文件,因此它不应该与用于应用程序的其他任何现有的测试框架冲突的方式。
(顺便说一句,我强烈建议使用QtCore甚至应用程序的非GUI部分。这是好得多的工作。)
Answer 8:
为了扩大mlvljr的和乔的解决方案,我们甚至可以支持每一个测试类完整QtTest选项,而仍运行在所有批次加日志记录:
usage:
help: "TestSuite.exe -help"
run all test classes (with logging): "TestSuite.exe"
print all test classes: "TestSuite.exe -classes"
run one test class with QtTest parameters: "TestSuite.exe testClass [options] [testfunctions[:testdata]]...
头
#ifndef TESTRUNNER_H
#define TESTRUNNER_H
#include <QList>
#include <QTimer>
#include <QCoreApplication>
#include <QtTest>
#include <QStringBuilder>
/*
Taken from https://stackoverflow.com/questions/1524390/what-unit-testing-framework-should-i-use-for-qt
BEWARE: there are some concerns doing so, see https://bugreports.qt.io/browse/QTBUG-23067
*/
class TestRunner : public QObject
{
Q_OBJECT
public:
TestRunner() : m_overallResult(0)
{
QDir dir;
if (!dir.exists(mTestLogFolder))
{
if (!dir.mkdir(mTestLogFolder))
qFatal("Cannot create folder %s", mTestLogFolder);
}
}
void addTest(QObject * test)
{
test->setParent(this);
m_tests.append(test);
}
bool runTests(int argc, char * argv[])
{
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()
{
// BEWARE: we assume either no command line parameters or evaluate first parameter ourselves
// usage:
// help: "TestSuite.exe -help"
// run all test classes (with logging): "TestSuite.exe"
// print all test classes: "TestSuite.exe -classes"
// run one test class with QtTest parameters: "TestSuite.exe testClass [options] [testfunctions[:testdata]]...
if (QCoreApplication::arguments().size() > 1 && QCoreApplication::arguments()[1] == "-help")
{
qDebug() << "Usage:";
qDebug().noquote() << "run all test classes (with logging):\t\t" << qAppName();
qDebug().noquote() << "print all test classes:\t\t\t\t" << qAppName() << "-classes";
qDebug().noquote() << "run one test class with QtTest parameters:\t" << qAppName() << "testClass [options][testfunctions[:testdata]]...";
qDebug().noquote() << "get more help for running one test class:\t" << qAppName() << "testClass -help";
exit(0);
}
foreach(QObject * test, m_tests)
{
QStringList arguments;
QString testName = test->metaObject()->className();
if (QCoreApplication::arguments().size() > 1)
{
if (QCoreApplication::arguments()[1] == "-classes")
{
// only print test classes
qDebug().noquote() << testName;
continue;
}
else
if (QCoreApplication::arguments()[1] != testName)
{
continue;
}
else
{
arguments = QCoreApplication::arguments();
arguments.removeAt(1);
}
}
else
{
arguments.append(QCoreApplication::arguments()[0]);
// log to console
arguments.append("-o"); arguments.append("-,txt");
// log to file as TXT
arguments.append("-o"); arguments.append(mTestLogFolder % "/" % testName % ".log,txt");
// log to file as XML
arguments.append("-o"); arguments.append(mTestLogFolder % "/" % testName % ".xml,xunitxml");
}
m_overallResult |= QTest::qExec(test, arguments);
}
}
QList<QObject *> m_tests;
int m_overallResult;
const QString mTestLogFolder = "testLogs";
};
#endif // TESTRUNNER_H
自己的代码
#include "testrunner.h"
#include "test1"
...
#include <QDebug>
int main(int argc, char * argv[])
{
TestRunner testRunner;
//your QTest compatible class here
testRunner.addTest(new Test1);
testRunner.addTest(new Test2);
...
bool pass = testRunner.runTests(argc, argv);
qDebug() << "Overall result: " << (pass ? "PASS" : "FAIL");
return pass?0:1;
}
Answer 9:
如果您使用的是Qt,我会建议使用QtTest,由于有设施测试用户界面和简单易用。
如果你使用QtCore,你也许可以做到没有STL。 我经常发现的Qt类更容易比STL同行使用。
Answer 10:
我刚刚被玩弄这一点。 在QtTest使用谷歌测试我们的主要优势是,我们确实在Visual Studio中所有的UI开发。 如果您使用Visual Studio 2012和安装谷歌测试适配器 ,你可以得到VS识别测试,包括他们的测试资源管理器。 这是伟大的开发者能够为他们编写的代码使用,因为谷歌测试是可移植的,我们也可以将测试添加到我们的Linux构建的结束。
我希望在未来++,有人将增加对C支持的并发测试工具,C#有,像一个NCrunch , 贾尔斯和ContinuousTests 。
当然,你可能会找人替VS2012,增加了测试适配器QtTest支持写入另一个适配器在这种情况下,这种优势就会消失! 如果有人有兴趣在此有一个很好的博客文章创作一个新的Visual Studio单元测试适配器 。
Answer 11:
对于Visual Studio测试适配器工具支持与QtTest框架使用Visual Studio的扩展: https://visualstudiogallery.msdn.microsoft.com/cc1fcd27-4e58-4663-951f-fb02d9ff3653
文章来源: What unit-testing framework should I use for Qt? [closed]