web-dev-qa-db-ja.com

Qt:複数のクラスでユニットテストを編成するにはどうすればよいですか?

Qtユニットテスト(サブ)プロジェクトがあり、1つのクラスが生成されます(メインは_QTEST_APPLESS_MAIN_によって生成されます)。これは、QtCreator内からコンソールアプリとして開始できます。

Q:この特定のプロジェクトにテストケースとしてクラスを追加するにはどうすればよいですか。

  1. これらのクラスに「テスト」スロット(_private Q_SLOTS_)しかない場合、メソッドは呼び出されず、_QTEST_APPLESS_MAIN_を持つクラスのメソッドのみが呼び出されます。
  2. main(..)は1つしか存在できないため、プロジェクト内の複数のクラスで_QTEST_APPLESS_MAIN_を使用することはできません(正しいですか?)
  3. もちろん、(追加の)クラスのスロットをmainを含む1つのクラスに手動で「配線」することはできますが、これは非常に面倒です。

では、単体テストプロジェクトで複数のクラスに対して単体テストを実行するための最良の方法は何ですか?

PS: " プロジェクトでのQTユニットテストの使用-競合するmain(...)関数 " a ブログが言及されています ただし、ソリューションを説明するZipをダウンロードできません。

Qt Unit Test subproject

30
Horst Walter

リンクしたソリューションによると、単一のQtユニットテストプロジェクト内で2つ(またはそれ以上)のクラスのテストを実行する方法は、テストする各クラスに対応するテストクラスがあり、カスタム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ファイルを含めることを忘れないでください。

21
RA.

受け入れられた回答に基づいており、C++ 11を使用している場合は、ラムダを使用したソリューションに興味がある可能性があります。毎回同じコードを書く必要がなくなります。ラムダを関数に置き換えることはできますが、ラムダの方がクリーンだと思います。

#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();
};
20

これと同じ答えを検索して、 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;
}
7
Aba

私のやり方:

  • 一般的な「サブディレクトリ」プロジェクトを作成します。
  • テスト対象のコードをC++ライブラリサブプロジェクトに配置します。
  • 単体テストプロジェクトを使用する代わりに、コンソールアプリケーションサブプロジェクトを使用します。
  • ライブラリをこのコンソールアプリケーションにリンクします。階層の最上位にある.proファイルの依存関係を処理することを忘れないでください。
  • このコンソールサブプロジェクトで、必要な数のテストクラスを定義し、この同じプロジェクトのメインでそれらを起動します。

私は基本的に この投稿 のわずかなバリエーションを作りました。

1
Doplusplus