1

I saw that Qt supports a data function associated to a test function.

http://qt-project.org/doc/qt-4.8/qtestlib-tutorial2.html

Is it possible to have some similar type of data function for multiple tests ?

Example:

void Test::Test1()
{
  SomeClass::SomeDataType a;
  a.manyValuesComplicatedToSet = 1;
  SomeOtherClass::SomeOtherDataType b;
  b.manyValuesComplicatedToSet = 2;

  QVERIFY(SomeTestClass::someFunction(a,b)== 3);
}

void Test::Test2()
{
  SomeClass::SomeDataType a;
  a.manyValuesComplicatedToSet = 1;
  SomeOtherClass::SomeOtherDataType b;
  b.manyValuesComplicatedToSet = 2;

  QVERIFY(SomeTestClass::someOtherFunction(a,b)== 5);
}

I would love to be able to set the data above in a common data function, so that I would not type it all every time.

Is that possible ?

david
  • 187
  • 8
Thalia
  • 13,637
  • 22
  • 96
  • 190
  • 1
    [this answer](http://stackoverflow.com/a/12687255/2642204) suggests that `QTestLib` doesn't support test fixtures. So it seems it is currently not possible. The answer is old, but from looking at the docs nothing has changed in this matter. – BartoszKP Aug 20 '14 at 22:06

2 Answers2

3

It's possible by extracting your test data into a separate function and then calling that function from your _data functions:

void Test::Test1()
{
    QFETCH(SomeClass::SomeDataType, a);
    QFETCH(SomeOtherClass::SomeOtherDataType, b);

    QCOMARE(SomeTestClass::someFunction(a,b), 3);
}

void Test::Test1_data()
{
    createTestData();
}

void Test::Test2()
{
    QFETCH(SomeClass::SomeDataType, a);
    QFETCH(SomeOtherClass::SomeOtherDataType, b);

    QCOMPARE(SomeTestClass::someOtherFunction(a,b), 5);
}

void Test::Test2_data()
{
    createTestData();
}

void Test::createTestData()
{
    QTest::addColumn<SomeClass::SomeDataType>("a");
    QTest::addColumn<SomeOtherClass::SomeOtherDataType>("b");

    SomeClass::SomeDataType a;
    a.manyValuesComplicatedToSet = 1;
    SomeOtherClass::SomeOtherDataType b;
    b.manyValuesComplicatedToSet = 2;
    QTest::newRow("test 1") << a << b;
}

Note that createTestData() in my example above is not defined as a slot. Also note that to pass SomeClass::SomeDataType and SomeOtherClass::SomeOtherDataType as test data parameters, you must call Q_DECLARE_METATYPE on them.

RA.
  • 7,542
  • 1
  • 34
  • 35
  • I ended up doing a simplified version... not sure if it is "proper" but I just created regular functions that create data. GTest and boost recreate data from text fixtures every time, I imagine that QTest is no different ? In which case simply calling a function to generate the data would be enough ? – Thalia Aug 27 '14 at 16:13
  • @Thalia Yes, that would work, too. The data-driven tests are most useful when you want to test the same functions with many sets of data (corresponding to many rows in the test table). If you just want to test your function with one set of data, a simple function to generate the data is good enough. – RA. Aug 27 '14 at 16:51
0

There are many ways to skin this cat.

One easy-to-configure example is given below... (warning: pseudocode ahead)

void Tester::LoadTestTuples(QString filename)
{
   // ... open file
   while(fileHandle.ok())
   {
      fileHandle >> a >> b >> c >> expectedResult;
      // this is your own test data file - all tuples are expected to be read.
      QCOMPARE(TestAddFunction(a, b, c), expectedResult);
   }
}

and do this:

$ touch testData.txt
$ echo "1 4 5 10" >> testData.txt

Internally, we prefer to add testData.txt to a qrc file and have it compiled in, but that's a preference.

You can extend this to provide specific test-scenarios and strictness of checks.. like:

$ echo "test_add 1 4 5 10 exit_on_fail" >> testData.txt
$ echo "test_divide 100 3 1 33 approximate_compare" >> testData.txt

(with appropriate modifications like this...)

{
   // format: testType = function to test. testResponseType = what to do when it fails.
   // a, b, c = inputs. expectedResult = comparison.
   // example test_add(1, 4, 5) = 1 + 4 + 5 = compared with 10. Strict.
   // example test_divide(100, 1, 3) = (100/1)/3 = compared with 33. Approximate, don't fail. 
   fileHandle >> testType >> a >> b >> c >> expectedResult >> testResponseType;
   TestResponseType type = ResponseFromString(testResponseType);
   switch (TestTypeFromString(testType))
   {
    case Test_Add: return Test<type>(a, b, c, expectedResult, Add);
    case Test_Divide: return Test<type>(a, b, c, expectedResult, Divide);
    default: return false;
   }
}
// ...

template <int TestResponseType> //generic test-fn template
bool Test(int a, int b, int c, int result, TestFunctor& fn)
{
}
template <> // specialized for each "reaction" type...
bool Test<Warn>(int a, int b, int c, int result, TestFunctor& fn)
{
    return QCOMPARE_WARN(fn(a, b, c) == result);
}
template <>
bool Test<FailOnError>(int a, int b, int c, int result, TestFunctor& fn)
{
    QCOMPARE_ASSERT(fn(a, b, c) == result);
    return true;
}
Fox
  • 2,078
  • 17
  • 18