Как QTEST_MAIN автоматически настраивает все для запуска тестов? - PullRequest
0 голосов
/ 30 января 2020

Я работаю над существующим проектом, написанным на C ++, точка входа для приложения:

QTEST_MAIN(className)

С документация, которую я прочитал , это создаст стандартная функция C main(), но не совсем понятно, как называются тесты приложения или каков порядок вызова или как его настроить.

Взгляд на класс в проекте У меня нет конструктора класса; сам класс является производным от QObject. У него 23 приватных слота: один из них называется «initTestCase»; остальные - это различные тесты, заканчивающиеся на «Test».

Слот «InitTestCase» содержит один вызов для установки правил фильтрации журналов, и это все. Когда проект скомпилирован и запущен, он выполняет тесты, но я не вижу, как и откуда поступает порядок.

Что на самом деле делает макрос QTEST_MAIN в моей программе, как настраиваются слоты и как он узнает, какие тесты выполнить?

1 Ответ

0 голосов
/ 30 января 2020

QTEST_MAIN перенаправляет в QTEST_MAIN_IMPL:

#define QTEST_MAIN(TestObject) \
int main(int argc, char *argv[]) \
{ \
    QTEST_MAIN_IMPL(TestObject) \
}

Этот QTEST_MAIN_IMPL отличается в зависимости от того, какое QApplication вам нужно (Widgets, Gui или Core). Для виджетов это выглядит так:

#define QTEST_MAIN_IMPL(TestObject) \
    TESTLIB_SELFCOVERAGE_START(#TestObject) \
    QT_PREPEND_NAMESPACE(QTest::Internal::callInitMain)<TestObject>(); \
    QApplication app(argc, argv); \
    app.setAttribute(Qt::AA_Use96Dpi, true); \
    QTEST_DISABLE_KEYPAD_NAVIGATION \
    TestObject tc; \
    QTEST_SET_MAIN_SOURCE_PATH \
    return QTest::qExec(&tc, argc, argv);

QTest :: qExe c определено qtestcase. cpp:

int QTest::qExec(QObject *testObject, int argc, char **argv)
{
    qInit(testObject, argc, argv);
    int ret = qRun();
    qCleanup();
    return ret;
}

В qInit (), установлен currentTestObject.

В qRun () создан экземпляр TestMethods , и в его конструкторе мы находим этот l oop:

const QMetaObject *metaObject = o->metaObject();
const int count = metaObject->methodCount();
m_methods.reserve(count);
for (int i = 0; i < count; ++i) {
     const QMetaMethod me = metaObject->method(i);
     if (isValidSlot(me))
         m_methods.push_back(me);
}

isValidSlot () реализован следующим образом:

static bool isValidSlot(const QMetaMethod &sl)
{
    if (sl.access() != QMetaMethod::Private || sl.parameterCount() != 0
        || sl.returnType() != QMetaType::Void || sl.methodType() != QMetaMethod::Slot)
        return false;
    const QByteArray name = sl.name();
    return !(name.isEmpty() || name.endsWith("_data")
        || name == "initTestCase" || name == "cleanupTestCase"
        || name == "init" || name == "cleanup");
}

Наконец, TestMethods :: invokeMethod () is Вызванный, который явно проверяет сначала initTestCase и запускает его:

QTestResult::setCurrentTestFunction("initTestCase");
if (m_initTestCaseDataMethod.isValid())
    m_initTestCaseDataMethod.invoke(testObject, Qt::DirectConnection);

Аналогично, он проверяет cleanupTestCase в конце.

...