天天看点

QT单元测试

A basic QTestLib and qExec example (for engineers with experience in Q.A., not Qt!)

Posted March 10, 2010

Filed under: C/C++, QA, Qt |

When doing a software QA project, you have to be ready to set up and design tests in a variety of different programming (and scripting) languages — to best integrate the automated tests with the rest of the project.  I've worked in C/C++, but I'm far from being an expert on the subject. So I can end up wasting time on points that would be extremely simple for an engineer who works in C or C++ every day. And since I wasted my time on this, I'm posting my notes so that you won't have to do the same.

I recently added some tests to the automated build of a C++ project that uses Qt, which has a built-in unit testing framework: QTestLib. QTestLib seems reasonably well-designed in terms of features. There were just a couple of points I felt were missing from the tutorial, so I'm posting a few remarks for the sake of Q.A. engineers who need to dive straight into the Qt unit test framework. (Apologies in advance to C/C++ developers who will undoubtedly find these points laughably trivial…)

I'm assuming here that you've already done at least the first chapter of the tutorial.  If not, go do it now — it's very short.

Done? OK, let's get started. My #1 problem with the tutorial is that it explains how to create a stand-alone application that runs a single QTest class, but doesn't explain how to create an application that will use QExec to run a series of QTest test suites. Like so many things in software engineering, it's very simple (once you know the trick).  And today I'm going to tell you the trick!

I've gotten used to programming in Java, and I'd forgotten that a C application is only allowed to have one main() function.  Unlike in Java, if you have two program files that each have a main() function, then you can't link them together into a single application. (This is because main() is global instead of being a class-specific method.)

Normally this isn't a problem — just don't write any main() functions except for the main main().  Except that the tutorial just shows you how to create a test class (in a single file) with an auto-generated main() function.  So how do I write a central application (with its own main) that can execute that set of tests in the "TestQString" class — plus execute the tests in other tests classes? The tutorialsays this:

Finally, to make our test case a stand-alone executable, the following two lines are needed:

QTEST_MAIN(TestQString)

#include "testqstring.moc"

The QTEST_MAIN() macro expands to a simple main() method that runs all the test functions. Note that if both the declaration and the implementation of our test class are in a .cpp file, we also need to include the generated moc file to make Qt's introspection work.

This is helpful as a start, but it kind of left me asking: What if I don't want to put the declaration and the implementation in the same file? Then how do I include "the generated moc file" (whatever the hell that is)?

Answer: you don't need to do anything — the generated main() function is included automatically if you have a separate header file for declarations.  Create a "TestQString.h" file and put the declaration part in it:

#include

class TestQString: public QObject

{

Q_OBJECT

private slots:

void toUpper();

};

Then add the #include "TestQString.h" line in the .cpp file, plus add "HEADERS += TestQString.h" to your .pro file.  The generated parts will take care of themselves in the "qmake" step.  (Again, sorry to belabor an obvious point, but I'm not the only one who was confused by this.)

Then there was one more (not-stated-in-the-tutorial-but-obvious-in-retrospect) point that I had to figure out for myself: The test class doesn't need the generated main() in order to run the tests in sequence. The auto-generated main() runs the test in sequence — including the set-up and tear-down steps — but apparently Qtest::qExec does the same thing, without using the auto-generated main() function to do it. So if you're using Qtest::qExec, you can just leave off the QTEST_QMAIN() entirely.

And — if you'd like to allow both options — just put the QTEST_QMAIN() statement in a separate .cpp source file (not the one where you implemented your tests). Then you can write two different project files — one that includes the source file with QTEST_QMAIN() (to build your tests in stand-alone mode), and one that leaves that file off of the SOURCES list (for when you want your tests to be run by a larger application).

综上所述,只须修改成如下方式即可:

int main(int argc, char *argv[])

{

    TestStr2num test1;

QTest::qExec(&test1);

}

继续阅读