6.0.0-rc4Source

Writing Tests with Nt Test

How to write, build and run a test, and the macros Nt Test provides.

A test is a QObject with Q_OBJECT whose private slots are the test functions. ntmoc has to process the class: that is how Nt Test finds the slots. The usual form is a .cpp file that includes its own moc output:

#include <QSignalSpy>
#include <QTest>

class Counter : public QObject {
    Q_OBJECT
public:
    int value() const { return m_value; }
    void setValue(int value) {
        if (value == m_value)
            return;
        m_value = value;
        emit valueChanged(value);
    }

signals:
    void valueChanged(int value);

private:
    int m_value = 0;
};

class TestCounter : public QObject {
    Q_OBJECT

private slots:
    void init() { m_counter.setValue(0); }

    void startsAtZero() { QCOMPARE(Counter().value(), 0); }

    void emitsOnChange() {
        QSignalSpy spy(&m_counter, &Counter::valueChanged);
        m_counter.setValue(5);
        m_counter.setValue(5);
        QCOMPARE(spy.count(), 1);
        QCOMPARE(spy.takeFirst().at(0).toInt(), 5);
    }

    void toHex_data() {
        QTest::addColumn<int>("value");
        QTest::addColumn<QByteArray>("hex");

        QTest::newRow("zero") << 0 << QByteArray("0");
        QTest::newRow("byte") << 255 << QByteArray("ff");
    }

    void toHex() {
        QFETCH(int, value);
        QFETCH(QByteArray, hex);
        QCOMPARE(QByteArray::number(value, 16), hex);
    }

private:
    Counter m_counter;
};

QTEST_MAIN(TestCounter)
#include "tst_counter.moc"

Link Nt::Test and enable moc for the target:

add_executable(tst_counter tst_counter.cpp)
target_link_libraries(tst_counter PRIVATE Nt::Test)
nt_enable_automoc(tst_counter)
add_test(NAME tst_counter COMMAND tst_counter)

The executable returns the number of failed test functions, or 127 if that is higher.

Test Functions

Every private slot that returns void and takes no arguments runs, in the order of declaration, except for these special ones:

fails, no test function runs.

fails, that test function does not run.

test function runs for every global row.

Slots inherited from a base class that ntmoc has seen run first.

Data-Driven Tests

A _data function builds a table with QTest::addColumn() and QTest::newRow(), and the test function reads the current row with QFETCH(). See the toHex test in the example above.

Macros

The macros that report a failure return from the calling function, so they only work in a function that returns void. To check from a helper function, follow the call with QTest::currentTestFailed().

function it skips the test function, and in initTestCase() every test function.

a known failure, for the row dataTag or for all rows if it is empty. mode is Abort or Continue. If the check passes, the test fails.

column in the current row. The row of initTestCase_data() is used if the test function has no such column.

works in init() and cleanup() too.

expression throws a Type.

data file. See QTest::qFindTestData().

run of the class. Nt has no GUI module, so it is the same as QTEST_GUILESS_MAIN.

object, for tests that need no event loop.

Fails unless the relation holds, and prints both values.

Like QVERIFY, but first processes events until the condition is true or five seconds have passed.

The same, with the timeout in milliseconds as the last argument.

Running a Test

Name test functions on the command line to run only those, and add a data tag to run one row: ./tst_counter toHex:zero. A row of global and local data is global:local. The options are:

output if it is -. Repeat it for several logs. format is txt, junitxml or tap.

output, or of a following -o file.