Qt: запускает модульные тесты из нескольких тестовых классов и суммирует вывод всех из них

Qt поставляется с QTest, и есть некоторые документы: например, официальный учебник.

Однако QTest предлагает организовать модульные тесты в виде отдельных исполняемых файлов. Для этого есть специальный макрос, который генерирует main(): QTEST_MAIN()

Честно говоря, мне очень не нравится этот подход: как правило, гораздо более полезно запускать все тесты сразу, чтобы убедиться, что последние изменения ничего не нарушили. Иногда полезно маскировать некоторые тесты или выполнять отдельные тесты, но это исключение, а не правило.

Итак, я хочу запустить все тесты сразу. Хорошо, я могу написать свой собственный main(), который выполняет все тесты, которые я хочу, скажем так:

int main(int argc, char **argv)
{
   int status = 0;

   //-- run all tests
   {
      TestHTCodecISO14230 tc;
      status |= QTest::qExec(&tc, argc, argv);
   }

   {
      TestHTDataMsg tc;
      status |= QTest::qExec(&tc, argc, argv);
   }

   return status;
}

И он запускает все тесты, но проблема в том, что у меня нет удобного резюме всех тестов. Скажем, для двух тестов выше у меня есть два отдельных резюме:

********* Start testing of TestHTCodecISO14230 *********
Config: Using QtTest library 5.4.1, Qt 5.4.1 (i386-little_endian-ilp32 shared (dynamic) release build; by GCC 4.6.1)
PASS   : TestHTCodecISO14230::initTestCase()
PASS   : TestHTCodecISO14230::decode_summary()
PASS   : TestHTCodecISO14230::encode()
PASS   : TestHTCodecISO14230::decode_encoded()
PASS   : TestHTCodecISO14230::cleanupTestCase()
Totals: 5 passed, 0 failed, 0 skipped, 0 blacklisted
********* Finished testing of TestHTCodecISO14230 *********
********* Start testing of TestHTDataMsg *********
Config: Using QtTest library 5.4.1, Qt 5.4.1 (i386-little_endian-ilp32 shared (dynamic) release build; by GCC 4.6.1)
PASS   : TestHTDataMsg::initTestCase()
PASS   : TestHTDataMsg::test1()
PASS   : TestHTDataMsg::cleanupTestCase()
Totals: 3 passed, 0 failed, 0 skipped, 0 blacklisted
********* Finished testing of TestHTDataMsg *********

Тот факт, что возвращенный status будет отличным от нуля в случае ошибки, безусловно, полезен, но было бы гораздо более полезно, если бы у меня есть сводка:

Totals: 8 passed, 0 failed, 0 skipped, 0 blacklisted

Из того, что я вижу, это невозможно: я не могу найти способ программно получить количество пройденных, неудачных, пропущенных и занесенных в черный список тестов: qExec() - это просто функция в пространстве имен QTest, так что невозможно собрать дополнительную информацию после ее выполнения.

Ну, можно разобрать выходную строку, но, ugh...

Для меня это выглядит плохой дизайн. Было бы, вероятно, гораздо лучше сделать QTest как класс, затем сделать его экземпляр и передать некоторые классы тестов. Затем из экземпляра можно было собрать некоторую дополнительную информацию.

Или, может быть, я что-то пропустил.

Итак, возникает вопрос: возможно ли с QTest иметь итоговый вывод всех классов unit test?

Ответ 1

Как я писал в своем комментарии, я бы построил свои тестовые классы следующим образом:

class MyTests: public QObject
{
    Q_OBJECT
public:
    MyTests() : m_executed(0), m_failed(0)
private slots:
    [..]
    // This function will be called after each test
    void cleanup()
    {
        m_executed++;
        if (currentTestFailed()) {
            m_failed++;
        }        
    }

    // Output the summary of the test execution.
    void report() const
    {
        qDebug() << "Totals:"
                 << m_executed - m_failed  << "passed,"
                 << m_failed << "failed";
    }
private:
    int m_executed;
    int m_failed;
};

Если у вас несколько экземпляров класса MyTests, вы можете расширить его API и суммировать результаты выполнения, выдавая глобальный отчет о выполнении теста. Просто используйте всю силу классов С++.