> ## Content Index
> Fetch the complete content index at: https://www.smallstepsystems.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# QCOMPARE with Custom Qt Types
- URL: https://www.smallstepsystems.com/qcompare-with-custom-qt-types/
- Published: 2019-08-05T08:00:17.000Z
- Updated: 2026-01-25T13:43:39.000Z
- Author: Burkhard Stubert

When you write unit tests, you will have to compare the actual value and the expected value. A simplified example with `QString`s would look like this.

```
void MyTest::testQCompare() {
    auto actualStr = QString{"abba"};
    auto expectedStr = QString{"juhu"};
    QCOMPARE(actualStr, expectedStr);
}
```

When you run this unit test, the `QTest` framework will print the actual value `"abba"` and the expected value `"juhu"`. This is often enough to know what went wrong.

```
FAIL!  : MyTest::testQCompare() Compared values are not the same
   Actual   (actualStr)  : "abba"
   Expected (expectedStr): "juhu"
```

If two values of a custom type differ, the `QTest` framework will only print the first line: *Compared values are not the same*. This is not very helpful. How can you make `QCOMPARE` print the actual and expected for custom types as well?

The class `QCanBusFrame` is a good example of a custom type. It lacks an equality operator and doesn't produce a meaningful output when `QCOMPARE` fails. The next unit tests exhibits exactly this behaviour.

```
void MyTest::testQCompare()
{
    auto frame1 = QCanBusFrame{0x18ef0201U, QByteArray::fromHex("018A")};
    auto frame2 = QCanBusFrame{0x18ef0301U, QByteArray::fromHex("0153")};
    QCOMPARE(frame1, frame2);
}
```

The compilation of the unit tests fails with an error caused by `QCOMPARE` located at *mytest.cpp:74:5*.

```
qtestcase.h: In instantiation of ‘bool QTest::qCompare(const T&,
    const T&, const char*, const char*, const char*, int) 
    [with T = QCanBusFrame]’:
mytest.cpp:74:5:   required from here
qtestcase.h:359:34: error: no match for ‘operator==’ (operand types
    are ‘const QCanBusFrame’ and ‘const QCanBusFrame’)
    return compare_helper(t1 == t2, "Compared values are not the
                                     same",
```

The third error message says that `QCanBusFrame` has no equality operator, which is needed at location *qtestcase.h:359:34*. The function `compare_helper` is passed the result of the comparison `t1 == t2`, whether the `QCanBusFrame`s `t1` and `t2` are equal.

Two CAN frames are equal, if their frame IDs and payloads are equal. The equality operator has global scope.

```
bool operator==(const QCanBusFrame &frame1, const QCanBusFrame &frame2)
{
    return frame1.frameId() == frame2.frameId() && 
        frame1.payload() == frame2.payload();
}
```

The unit test compiles fine now, but produces the not so useful output that the two CAN frames are not the same.

```
FAIL!  : MyTest::testQCompare() Compared values are not the same
```

The complete call of `compare_helper` gives you a clue how to make the output more instructive.

```
return compare_helper(t1 == t2, "Compared values are not the same",
                      toString(t1), toString(t2), actual, expected,
                      file, line);
```

The function calls` toString(t1)` and `toString(t2)` try to convert the CAN frames `t1` and `t2` to C strings. As there is no specific overload for `QCanBusFrame`s

```
char *toString(const QCanBusFrame &frame);
```

the compiler chooses the general overload

```
template<> char *toString(const T &t)
```

This general overload returns `nullptr` when `T` equals `QCanBusFrame`. The function `compare_helper` calls the function `QTestResult::compare` passing `nullptr` to the arguments `val1` and `val2`. If the comparison returns `false` and if one of the values is `nullptr`, `QTestResult::compare` won't print the actual and expected value but only "Compared values are not the same".

The overload `toString(const char *str)` in `qtestcase.cpp` is a good blueprint for your own overload.

```
char *toString(const QCanBusFrame &frame)
{
    auto src = QByteArray::number(frame.frameId(), 16) + "#" +
        frame.payload().toHex();
    char *dst = new char[src.size() + 1];
    return qstrcpy(dst, src.data());
}
```

The variable `src` contains the CAN frame in the format `id#payload` \- as described in my previous post [Printing Custom Qt Types with qDebug()](https://www.smallstepsystems.com/printing-custom-qt-types-with-qdebug/). The variable `dst` is a newly created array of `char`. The function `qstrcpy` copies the contents of `src` into `dst`.

Returning a pointer to a `char` array created by `new` smells of a memory leak. It is not, because `QTestResult::compare` deletes the `char` arrays created by `toString`. This solution is certainly not foolproof, but works if used with caution.

Note that your overload must be declared globally. Putting it in the `QTest` namespace doesn't work.

When you run the unit test, it will print the instructive message you worked so hard for.

```
FAIL!  : MyTest::testQCompare() Compared values are not the same
   Actual   (frame1): 18ef0201#018a010000000000
   Expected (frame2): 18ef0301#0153020000000000
```