[Solved] QTest framework: initialize data driven tests
-
I am using the QTest unit testing framework to unit test a class. I am using the data driven method like this:
private slots: void test(); void test_data();
That makes sure that my
test()
method is called as many times as I have created cases in mytest_data()
. Nice.There also is an
init()
and aninitTestCase()
method that you can use for initialization. However, those are generic. The one is called before each test, the second only before the first test. However, in my case, I am trying to test an object that can be initialized in different ways. What I would like to do, is initialize the object, run a testcase on it (created intest_data()
), and after the last test, destroy the object again to clean up for the next test.So, what I'd like to have is basically this:
private slots: //test 1 void test(); void test_data(); void test_init(); void test_cleanup(); //test 2 void test2(); void test2_data(); void test2_init(); void test2_cleanup();
So basically, give each test its own init and cleanup functions, though I could do without the cleanup one I guess.
I could prepend a special data point in the test data to trigger initialization inside the
test()
function itself, but that is a bit messy really. Any suggestions of better ways to do this? -
Why don't you just call test2_init() and test2_cleanup() from test() as needed?
-
How would I know inside test2() if the case I'm testing from test2_data() is the first or the last one?
-
I don't think you can know that.
Are you really having one test case only if you need to know which data set you are currently testing?
-
The idea is that one test (wich has one data set) can test one configuration of the object. For that, I need to initialize the object for that test, and I'd prefer to do that once per test, not once per test data.
Perhaps I could abuse test_data() to also do the initialization, but that would be relying on an undocumented order of calls to methods. For all I know, the framework first calls all _data methods and only then the actual tests.
-
OK, I think I found a solution.
In my declaration, I do this:
private slots: void init(); void test(); void test_data(); protected slots: //any invokable method will do, except for private slots void test_init(); void test_cleanup();
Then I implement the
init()
slot like this:void DateParseTest::init() { static QByteArray lastTestFunction; if (!lastTestFunction.isEmpty() && strcmp(lastTestFunction.data(), QTest::currentTestFunction()) == 0) return; if (!lastTestFunction.isEmpty()) { //we're going to run a new test, so run the test cleanup function of the previous test if it exists... QByteArray cleanupMethod(lastTestFunction); cleanupMethod += "_cleanup"; int index = metaObject()->indexOfMethod(cleanupMethod + "()"); if (index != -1) { metaObject()->invokeMethod(this, cleanupMethod.data(), Qt::DirectConnection); } } lastTestFunction = QTest::currentTestFunction(); //we're going to run a new test, so run the test init function if it exists... QByteArray initMethod(QTest::currentTestFunction()); initMethod += "_init"; int index = metaObject()->indexOfMethod(initMethod + "()"); if (index != -1) metaObject()->invokeMethod(this, initMethod.data(), Qt::DirectConnection); }
That is: I abused the init() call that is executed before running each and every test case to manually call a cleanup and and init method if those exist.
-
That should work, but I'd still just use the normal methods and split up the whole thing into different sets of unit tests.
-
I think it makes sense to test a single class from a single test. Anyway, I filed a "suggestion":https://bugreports.qt-project.org/browse/QTBUG-25975 in Jira to add this to the framework.