Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I'm working on an existing project written in C++, the entry point for the application is:

QTEST_MAIN(className)

From the documentation I've read, this will create a standard C main() function, but it isn't at all clear on how the application tests are called or what the call order is or how its set-up.

Looking at the class in the project I have, there is no class constructor; the class itself is derived from QObject. It has 23 private slots: one of these is called "initTestCase"; the others are various tests all ending in "Test".

The slot "InitTestCase" contains a single call to setup logging filter rules and that is all. When the project is compiled and run, it executes tests, but I cannot see how or where the order comes from.

What is the macro QTEST_MAIN actually doing in my program, how are the slots being set up, and how does it know which tests to execute?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
270 views
Welcome To Ask or Share your Answers For Others

1 Answer

QTEST_MAIN forwards to an QTEST_MAIN_IMPL:

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

This QTEST_MAIN_IMPL is different depending on what QApplication you need (Widgets, Gui or Core). For Widgets, it looks like this:

#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::qExec is defined qtestcase.cpp:

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

In qInit(), currentTestObject is set.

In qRun(), a TestMethods instance is created, and it its constructor, we find this loop:

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() is implemented thusly:

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");
}

Finally, TestMethods::invokeMethod() is called which explicitly checks for an initTestCase first and runs it:

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

Likewise, it checks for cleanupTestCase at the end.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...