Chapter 2: Data Driven Testing#
How to create data driven tests.
This chapter demonstrates how to execute a test multiple times with different test data.
So far, we have hard coded the data we wanted to test into our test function. If we add more test data, the function might look like this:
QCOMPARE(QString("hello").toUpper(), QString("HELLO")) QCOMPARE(QString("Hello").toUpper(), QString("HELLO")) QCOMPARE(QString("HellO").toUpper(), QString("HELLO")) QCOMPARE(QString("HELLO").toUpper(), QString("HELLO"))
To prevent the function from being cluttered with repetitive code, Qt Test supports adding test data to a test function. All we need is to add another private slot to our test class:
class TestQString(QObject): Q_OBJECT slots: = private() def toUpper_data(): def toUpper():
Writing the Data Function#
A test function’s associated data function has
_data appended to its name. Our data function looks like this:
def toUpper_data(self): QTest.addColumn<QString>("string") QTest.addColumn<QString>("result") QTest.newRow("all lower") << "hello" << "HELLO" QTest.newRow("mixed") << "Hello" << "HELLO" QTest.newRow("all upper") << "HELLO" << "HELLO"
First, we define the two elements of our test table using the
addColumn() function: a test string and the expected result of applying the
toUpper() function to that string.
Then, we add some data to the table using the
newRow() function. Each set of data will become a separate row in the test table.
newRow() takes one argument: a name that will be associated with the data set and used in the test log to identify the data set. Then, we stream the data set into the new table row. First an arbitrary string, and then the expected result of applying the
toUpper() function to that string.
You can think of the test data as a two-dimensional table. In our case, it has two columns called
result and three rows. In addition, a name and an index are associated with each row:
When data is streamed into the row, each datum is asserted to match the type of the column whose value it supplies. If any assertion fails, the test is aborted.
Rewriting the Test Function#
Our test function can now be rewritten:
def toUpper(self): QFETCH(QString, string) QFETCH(QString, result) QCOMPARE(string.toUpper(), result)
The TestQString::toUpper() function will be executed three times, once for each entry in the test table that we created in the associated TestQString::toUpper_data() function.
First, we fetch the two elements of the data set using the
QFETCH() takes two arguments: The data type of the element and the element name. Then, we perform the test using the
This approach makes it very easy to add new data to the test without modifying the test itself.
Preparing the Stand-Alone Executable#
And again, to make our test case a stand-alone executable, the following two lines are needed:
QTEST_MAIN(TestQString) from testqstring.moc import *
As before, the
QTEST_MAIN() macro expands to a simple main() method that runs all the test functions, and since 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.
Building the Executable#
You can build the test case executable using CMake or qmake.
Building with CMake#
Configure your build settings in your CMakeLists.txt file:
<Code snippet "/data/snapshot-qt5full-6.3/qt5/qtbase/tutorial2/CMakeLists.txt" not found>
Next, from the command line, run either
cmake or use the
qt-cmake convenience script located in
<Qt-prefix>/<version>/<platform>/bin/qt-cmake <source-dir> <build-dir> -G Ninja
Then, run your preferred generator tool to build the executable. Here, we’re using Ninja:
Building with qmake#
Configure your build settings in your
<Code snippet "/data/snapshot-qt5full-6.3/qt5/qtbase/tutorial2/tutorial2.pro" not found>
qmake, and, finally, run
make to build your executable:
Running the Executable#
Running the resulting executable should give you the following output:
********* Start testing of TestQString ********* Config: Using QtTest library %VERSION%, Qt %VERSION% PASS : TestQString::initTestCase() PASS : TestQString::toUpper(all lower) PASS : TestQString::toUpper(mixed) PASS : TestQString::toUpper(all upper) PASS : TestQString::cleanupTestCase() Totals: 5 passed, 0 failed, 0 skipped, 0 blacklisted, 0ms ********* Finished testing of TestQString *********