Important: Please read the Qt Code of Conduct -

[Solved] QTest issue creating object to test with

  • Hi Folks,

    I'm trying to wrap my head around unit tests. I have a small class used to create an SQLite interface, which will eventually be utilised by the rest of the application, for which I would like to write some unit tests. I have manually checked that the functions perform as required, so its a simple case of automatically verifying what I have already done.

    However, when I attempt to instantiate the backend as an object in my test class, I end up with a bunch of function undefined errors. What is strange is that the same method of instantiating the backend works fine in the full application...

    The backend class inherits from QSqlRelationalTableModel, for the code below I am using the data setup in the Books SQL demo.

    For reference, this is how I instantiate the class in the primary application, which works:

    int main(int argc, char *argv[]) {
        //set Library Paths
        QCoreApplication::addLibraryPath ("libs/");
        QApplication app(argc, argv);
        QQmlApplicationEngine engine;
        QApplication::connect(&engine, SIGNAL(quit()), QCoreApplication::instance(), SLOT(quit()) );
        SQLite_Backend *mData = new SQLite_Backend;
        //Setup the database query for the model
        QString data_query;
        data_query = "select, books.title, as auth_name, "
        data_query += " as genre_name, books.year, books.rating\n";
        data_query += "from books\n";
        data_query += "join authors on =\n";
        data_query += "join genres on = books.genre";
        engine.rootContext ()->setContextProperty ("Data", mData);
       return app.exec();

    The above code works perfectly, with data showing up in the dummy QML file I've been using to test.

    In my unit tests I would like to test each custom method of the class, i.e.

    • Can I add/remove records?
    • Can I add/remove tables?
    • Can I evaluate SQL Statements correctly

    As such I am presuming that I will need to create an instance of the backend, call its functions and compare the results with what is actually in the database. For now I can do that with a hard code. i.e.

    QCOMPARE(mData.getRowCount("books"), 5)

    When attempting to instantiate the backend inside a test case in the exact same way as above I end up with the following errors:

    SQLiteBackend_Test.cpp:31: undefined reference to `SQLite_Backend::SQLite_Backend(QObject*)'
    SQLiteBackend_Test.cpp:31: undefined reference to `SQLiteBackend_Test::mDbWrapper'
    SQLiteBackend_Test.cpp:36: undefined reference to `SQLiteBackend_Test::mDbWrapper'
    SQLiteBackend_Test.cpp:36: undefined reference to `SQLite_Backend::setDatabase(QString const&)'
    moc_SQLiteBackend_Test.cpp:84: undefined reference to `SQLiteBackend_Test::getRows()'

    Could anyone point me in the direction of what I am doing wrong?

    I have tried instantiating the database class in a test case (i.e. slot function), re-implementing a main, a class constructor, an initTestCase function. All of them result in the above errors.

    Hopefully I'm doing something silly here, but I'm stumped!

  • Did you add all required source files to the .pro file?
    Looks like at least that the implementation of SQLite_Backend is missing. Also the implementation of SQLiteBackend_Test::mDbWrapper and SQLiteBackend_Test::getRows are missing.

  • @koahnig

    At the moment I haven't included the SQLite_Backend files in the .pro, but am #include'ing the header to the library in the test class


    #include <QApplication>
    #include <QTest>
    #include <QtSql>
    #include "../dataModel/SQLite_Backend.h"
    class SQLiteBackend_Test : public QObject
    private slots:
        //Setup and Teardown
        void initTestCase();


    #include "SQLiteBackend_Test.h"
    void SQLiteBackend_Test::initTestCase() {
          SQLite_Backend *mTarget = new SQLite_Backend;
          mTarget->setDatabase ("/path/to/my/SQLite/Data/file");
    //Uncomment below to run this file as a standalone test case

    I will try including the test class in the .pro and report back, thanks for the pointer.

  • @Sam2304
    The application test is basically a special application. You need to link all required source files as in a normal application. Also you need to define all Qt modules in the .pro (probable at least QT += sql in your case).

    class SQLiteBackend_Test : public QObject
    private slots:
        //Setup and Teardown
        void initTestCase();
        int getRows() const;    // you did not declare and implementation is also missing
        ????    mDbWrapper( ... ); // you did not declare and implementation is also missing

    Also you have not declared the two missing methods and their implmenentation is mssing as well.
    Note: You need to check the skleletons I have added.
    Furthermore, it could be better to separate the functionality of those two missing methods from your test class.

  • @koahnig

    Thank You!!!

    Your advice got me to the point where a sample test actually runs!

    your pointer to the missing methods prompted me to clear out all the commented gumff from the class header and source, which revealed the missing methods. I'd been staring at this for so long I hadn't seen them.

    I removed those and things finally started compiling. Running make check runs the test, which is perfect!

    The test itself failed, but that's simply because the test code itself is malformed.

    Thank you so much for your assistance, I've been bouncing off a brick wall on this for a couple of days!

    Kindest Regards,

    p.s. I notice that if I comment out the includes in the test .pro file, the test still compiles and runs.. interesting!


  • @Sam2304

    you are welcome

    Well, sometimes "we programmers do not see the forest because of trees" ;)
    Glad, that it worked out for you.