33

我有一个 Qt 单元测试(子)项目,它为我生成一个类(主要由 生成QTEST_APPLESS_MAIN)。我可以从 Qt Creator 作为控制台应用程序启动它。

问:我如何向这个特定项目添加额外的类作为测试用例。

  1. 如果这些类只有“测试”槽(private Q_SLOTS),则不会调用方法,而只会调用具有QTEST_APPLESS_MAIN
  2. 由于只能有一个main(..),我不能QTEST_APPLESS_MAIN在项目中使用多个类(对吗?)
  3. 当然,我可以手动将(附加)类中的插槽与包含 的类“连接” main,但这非常乏味。

那么在单元测试项目中对多个类运行单元测试的最佳方法是什么?

PS:在“在项目中使用 QT 单元测试 - 冲突的 main(...) 函数中提到了一个博客,但是,我无法下载描述该解决方案的 zip。

Qt 单元测试子项目

4

6 回答 6

25

根据您链接到的解决方案,在单个 Qt 单元测试项目中完成测试两个(或多个)类的方法是确保要测试的每个类都有相应的测试类,并且您已经创建了一个自定义int main的执行每个测试类。

例如:

class TestClassA : public QObject
{
   Q_OBJECT
public:
   TestClassA();

   ...

private Q_SLOTS:
   void testCase1();
   ...
};

class TestClassB : public QObject
{
   Q_OBJECT
public:
   TestClassB();

   ...

private Q_SLOTS:
   void testCase2();
   ...
};

void TestClassA::testCase1()
{
   // Define test here.
}

void TestClassB::testCase2()
{
   // Define test here.
}

// Additional tests defined here.

// Note: This is equivalent to QTEST_APPLESS_MAIN for multiple test classes.
int main(int argc, char** argv)
{
   int status = 0;
   {
      TestClassA tc;
      status |= QTest::qExec(&tc, argc, argv);
   }
   {
      TestClassB tc;
      status |= QTest::qExec(&tc, argc, argv);
   }
   return status;
}

显然,不同的测试类可以分布在多个翻译单元中,然后简单地使用您的int main. 不要忘记包含适当的.moc文件。

于 2012-08-31T00:40:04.913 回答
21

基于接受的答案,如果您使用的是 C++11,您可能会对使用 lambdas 的解决方案感兴趣。它避免了您每次都编写相同的代码。虽然你可以用函数替换 lambda,但我认为 lambda 更干净。

#include <QtTest>

#include "test1.h"
#include "test2.h"


int main(int argc, char** argv)
{
   int status = 0;
   auto ASSERT_TEST = [&status, argc, argv](QObject* obj) {
     status |= QTest::qExec(obj, argc, argv);
     delete obj;
   };

   ASSERT_TEST(new Test1());
   ASSERT_TEST(new Test2());

   return status;
}

#ifndef TEST1_H
#define TEST1_H

样品测试

#include <QtTest>

class Test1 : public QObject
{
    Q_OBJECT

  private Q_SLOTS:
    void testCase1();
};
于 2014-05-05T19:01:41.807 回答
9

在寻找同样的答案时,我从http://qtcreator.blogspot.de/2009/10/running-multiple-unit-tests.html找到了一个非常好的解决方案。他使用一个容器创建了一个命名空间,该容器注册了所有创建的测试(通过 DECLARE_TEST 宏),然后使用它来运行列表中的所有测试。我重写了它以适合我的代码,并在此处发布我的版本(我的 Qt Creator 版本:4.1.0):

/* BASED ON
 * http://qtcreator.blogspot.de/2009/10/running-multiple-unit-tests.html
 */    
#ifndef TESTCOLLECTOR_H
#define TESTCOLLECTOR_H

#include <QtTest>
#include <memory>
#include <map>
#include <string>

namespace TestCollector{
typedef std::map<std::string, std::shared_ptr<QObject> > TestList;
inline TestList& GetTestList()
{
   static TestList list;
   return list;
}

inline int RunAllTests(int argc, char **argv) {
    int result = 0;
    for (const auto&i:GetTestList()) {
        result += QTest::qExec(i.second.get(), argc, argv);
    }
    return result;
}

template <class T>
class UnitTestClass {
public:
    UnitTestClass(const std::string& pTestName) {
        auto& testList = TestCollector::GetTestList();
        if (0==testList.count(pTestName)) {
            testList.insert(std::make_pair(pTestName, std::make_shared<T>()));
        }
    }
};
}

#define ADD_TEST(className) static TestCollector::UnitTestClass<className> \
    test(#className);

#endif // TESTCOLLECTOR_H

然后,只需在测试标头中添加 ADD_TEST(class) 行,如下所示:

#ifndef TESTRANDOMENGINES_H
#define TESTRANDOMENGINES_H

#include <QtTest>
#include "TestCollector.h"

class TestRandomEngines : public QObject
{
    Q_OBJECT

private Q_SLOTS:
    void test1();
};

ADD_TEST(TestRandomEngines)

#endif // TESTRANDOMENGINES_H

并且要运行所有测试,只需执行以下操作:

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

int main(int argc, char *argv[]) {
    auto nFailedTests = TestCollector::RunAllTests(argc, argv);
    std::cout << "Total number of failed tests: "
              << nFailedTests << std::endl;
    return nFailedTests;
}
于 2016-12-29T18:44:27.023 回答
3

我正在使用以下代码收集所有测试结果:

#include "testclassa.h"
#include "testclassb.h"
#include <QtTest>
#include <QDebug>

int main(int argc, char** argv){

    int failedTests = 0;
    TestClassA testClassA
    TestClassB testClassB
    failedTests += QTest::qExec(&testClassA, argc, argv);
    failedTests += QTest::qExec(&testClassB, argc, argv);

    if(failedTests > 0){
        qDebug() << "total number of failed tests: " << failedTests;
    }else{
        qDebug() << "all tests passed :)";
    }
    return failedTests;
}
于 2019-09-16T10:25:44.570 回答
1

我这样做的方式:

  • 创建一个通用的“子目录”项目。
  • 将要测试的代码放在 C++ 库子项目中。
  • 我没有使用单元测试项目,而是使用控制台应用程序子项目。
  • 将库链接到此控制台应用程序,不要忘记在层次结构顶部的 .pro 文件中处理依赖项。
  • 在这个控制台子项目中,定义任意数量的测试类,并在同一个项目的主项目中启动它们。

我基本上对这篇文章做了些许改动。

于 2017-02-08T06:37:40.233 回答
1

使用 CMake 而不是 QMake 构建,并添加两个测试目标。

add_executable(firstTest tst_testfirst.cpp)
add_test(NAME firstTest COMMAND firstTest)

add_executable(secondTest tst_testsecond.cpp)
add_test(NAME secondTest COMMAND secondTest)

tst_testfirst.cpp 和 tst_testsecond.cpp 都有自己的 QTEST_MAIN 行。

Qt Creator 将运行这两个测试类。如果您从命令行运行它们,则使用“ctest”运行测试。

于 2020-05-27T13:59:58.060 回答