Unit testing Qt:如何组织多个类的单元测试?

Unit testing Qt:如何组织多个类的单元测试?,unit-testing,qt4,qt-creator,Unit Testing,Qt4,Qt Creator,我有一个Qt单元测试(子)项目,它会生成一个类(main由QTEST\u APPLESS\u main生成)。我可以在Qt Creator中作为控制台应用程序启动它 问:我如何向这个特定项目添加额外的类作为测试用例 如果这些类只有“test”槽(private Q\u槽),则不会调用这些方法,只调用带有QTEST\u APPLESS\u MAIN的类的方法 由于只能有一个main(..),我不能在项目中对多个类使用QTEST\u APPLESS\u main(正确吗?) 当然,我可以用一个包含m

我有一个Qt单元测试(子)项目,它会生成一个类(main由
QTEST\u APPLESS\u main
生成)。我可以在Qt Creator中作为控制台应用程序启动它

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

  • 如果这些类只有“test”槽(
    private Q\u槽
    ),则不会调用这些方法,只调用带有
    QTEST\u APPLESS\u MAIN的类的方法
  • 由于只能有一个
    main(..)
    ,我不能在项目中对多个类使用
    QTEST\u APPLESS\u main
    (正确吗?)
  • 当然,我可以用一个包含
    main
    的类手动“连接”(附加)类中的插槽,但这非常繁琐 那么,在单元测试项目中,在几个类上运行单元测试的最佳方法是什么呢

    附言: 但是,在“”a中,我无法下载描述解决方案的zip文件


    根据您链接到的解决方案,在单个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;
    }
    

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

    基于公认的答案,如果您使用的是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
    
    #包括
    #包括“test1.h”
    #包括“test2.h”
    int main(int argc,字符**argv)
    {
    int status=0;
    自动断言测试=[&status,argc,argv](QObject*obj){
    状态|=QTest::qExec(obj、argc、argv);
    删除obj;
    };
    ASSERT_TEST(新Test1());
    ASSERT_TEST(新Test2());
    返回状态;
    }
    #ifndef测试1_H
    #定义TEST1_H
    
    样品试验

    #include <QtTest>
    
    class Test1 : public QObject
    {
        Q_OBJECT
    
      private Q_SLOTS:
        void testCase1();
    };
    
    #包括
    类Test1:公共QObject
    {
    Q_对象
    专用Q_插槽:
    void testCase1();
    };
    
    在搜索相同的答案时,我从中找到了一个非常好的解决方案。他用一个容器创建一个名称空间,该容器注册所有创建的测试(通过DECLARE_TEST宏),然后使用它运行列表上的所有测试。我重写了它以适应我的代码,并将我的版本发布在这里(我的Qt Creator版本:4.1.0):

    /*基于
    * http://qtcreator.blogspot.de/2009/10/running-multiple-unit-tests.html
    */    
    #ifndef测试收集器
    #定义TESTCOLLECTOR_H
    #包括
    #包括
    #包括
    #包括
    命名空间测试收集器{
    typedef std::map TestList;
    内联测试列表&GetTestList()
    {
    静态测试列表;
    退货清单;
    }
    内联int-RunAllTests(int-argc,char**argv){
    int结果=0;
    for(const auto&i:GetTestList()){
    结果+=QTest::qExec(i.second.get(),argc,argv);
    }
    返回结果;
    }
    模板
    类UnitTestClass{
    公众:
    UnitTestClass(常量std::string和pTestName){
    auto&testList=TestCollector::GetTestList();
    if(0==testList.count(pTestName)){
    insert(std::make_pair(pTestName,std::make_shared());
    }
    }
    };
    }
    #定义添加测试(类名)静态TestCollector::UnitTestClass\
    测试(#类名);
    #endif//TESTCOLLECTOR\u H
    
    然后,只需在测试头中添加add_测试(类)行,如下所示:

    #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
    
    #如果NDEF测试引擎#
    #定义TESTRANDOMENGINES\u H
    #包括
    #包括“TestCollector.h”
    类TestRandomEngines:公共QObject
    {
    Q_对象
    专用Q_插槽:
    void test1();
    };
    添加测试(TestRandomEngines)
    #endif//testrandom\u 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;
    }
    
    #包括“TestCollector.h”
    #包括
    int main(int argc,char*argv[]){
    auto-nFailedTests=TestCollector::RunAllTests(argc,argv);
    std::cout我这样做的方式:

    • 创建一个通用的“细分”项目。
    • 将测试代码置于C++库子项目中。
    • 我使用的不是单元测试项目,而是控制台应用程序子项目。
    • 将库链接到此控制台应用程序,不要忘记处理层次结构顶部.pro文件中的依赖项。
    • 在这个控制台子项目中,定义尽可能多的测试类,并在同一个项目的main中启动它们

    我基本上对做了一点改动。

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

    #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;
    }
    
    #包括“testclassa.h”
    #包括“testclassb.h”
    #包括
    #包括
    int main(int argc,字符**argv){
    int failedTests=0;
    TestClassA TestClassA
    TestClassB TestClassB
    failedTests+=QTest::qExec(&testClassA、argc、argv);
    failedTests+=QTest::qExec(&testClassB,argc,argv);
    如果(失败测试>0){
    
    qDebug()使用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_主线


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

    直截了当地说,我应该早点看一下QTEST_APPLESS_MAIN DEFINE。我刚刚注意到你是回答这个问题的人,他之前也对我的另一个问题发表了评论,所以我怀疑你可以很好地解释这一区别。如果你有两个单独的文件(.cpp和.h),你不需要包含.moc动态创建对象的原因是什么?您也可以传递一个引用,这样您就不必处理对象销毁。
    auto ASSERT_TEST=[&status,argc,argv](QObject&obj){status |=QTest::qExec(&obj,argc,argv)};ASSERT_TEST(Test1())
    @christopheis我只是喜欢在
    add_executable(firstTest tst_testfirst.cpp)
    add_test(NAME firstTest COMMAND firstTest)
    
    add_executable(secondTest tst_testsecond.cpp)
    add_test(NAME secondTest COMMAND secondTest)