Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Qt: run unit tests from multiple test classes and summarize the output from all of them

Qt comes with QTest, and there are some docs: for example, an official tutorial.

However, QTest encourages you to organize unit tests as separate executables. There is special macro for this, that generates main(): QTEST_MAIN()

To be honest, I really dislike this approach: generally, it is much more useful to run all tests at once, in order to make sure that recent changes haven't broken anything. Sometimes, it is useful to mask out some test or execute some individual test, but this is an exception, not the rule.

So, I want to run all the tests at once. Ok, I can write my own main() that executes all tests I want, say, like this:

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

And it does run all tests, but the problem is that I don't have convenient summary of all tests. Say, for the two tests above, I have two separate summaries:

********* 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 *********

The fact that returned status will be non-zero in case of error is surely helpful, but is would be much more helpful if I have summary as well:

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

From what I see, it is impossible: I can't find the way to programmatically get number of passed, failed, skipped and blacklisted tests: qExec() is just a function in the QTest namespace, so, it is impossible to gather some additional info after it executes.

Well, it is possible to parse the output string, but, ugh...

To me, it looks like poor design. It would be probably much better to make QTest as a class, then make instance of it and feed some test classes to it. Then, some additional information could be gathered from an instance.

Or, maybe I've missed something.

So, the question is: is it possible with QTest to have summary output of all unit test classes?

like image 402
Dmitry Frank Avatar asked Jun 23 '15 11:06

Dmitry Frank


People also ask

How do you write a unit test case in Qt?

Writing a Test Let's assume you want to test the behavior of our QString class. First, you need a class that contains your test functions. This class has to inherit from QObject: #include <QTest> class TestQString: public QObject { Q_OBJECT private slots: void toUpper(); };

What is Qt in testing?

Qt Test is a framework for unit testing Qt based applications and libraries. Qt Test provides all the functionality commonly found in unit testing frameworks as well as extensions for testing graphical user interfaces. Qt Test consists of about 6000 lines of code and 60 exported symbols.

Can unit tests depend on each other?

Tests should never depend on each other. If your tests have to be run in a specific order, then you need to change your tests. Instead, you should make proper use of the Setup and TearDown features of your unit-testing framework to ensure each test is ready to run individually.


1 Answers

As I wrote in my comment, I would construct my test classes in the following way:

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

If you have multiple instances of MyTests class, you can extend its API and sum up the execution results producing the global test execution report. Just use the whole strength of C++ classes.

like image 128
vahancho Avatar answered Oct 20 '22 04:10

vahancho