Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Using Qt Test and private members



  • Hello everyone

    For far too long I have been too lazy to properly using Qt Test in my development process and now I am starting to try to implement it. But I have hit a wall regarding private members.
    Let me illustrate with an example with a simple class I have made.

    class SqlComm : public QObject
    {
        Q_OBJECT
    public:
        SqlComm(QSqlDatabase _database, QObject* parent = nullptr);
    
        void setDatabase(const QString &&host, const QString &&database);
    
        void setUser(const QString &&user, const QString &&psswd);
    
        void connectToDB();
    
        unsigned int getNextDBSerial();
    
    protected:
        QSqlDatabase*    db;
        QSqlQuery*       query;
    };
    

    Since I am doing unit testing, my plan is to simplify the testing by making a QSqlDatabase stub, where I can return different results and answers to simulate actual response from the database. But the QSqlDatabase is a private member that I can not access to insert the stub.
    I have searched and found different answers:

    • Add a define changing private members into public (#define private public)

    • Do not use private members but use protected instead. Subclass my class and raise access level to public.

    • Use interface (I have not entirely understood this one yet)

    The two first options I feel is a bit dirty and third one seem overly complicated.

    How would you test this class?

    Regards
    Sebastian



    1. Why do you even have QSqlDatabase as a member? The fact that it is a pointer worries me even more
    2. "Use interface" is one of the possible solutions, the other alternative is to move the private members into a pimpl and just have different versions of the private class for test and production (see https://wiki.qt.io/D-Pointer)
    3. The easiest and, if you ask me, more robust way to actually test it is to add a test db (a sqlite database file if you don't have a full fledged test db server) to your project and have the test program run off it rather than the production one. It's the only real way to actually test what will happen in production


    1. Why do you even have QSqlDatabase as a member? The fact that it is a pointer worries me even more
    2. "Use interface" is one of the possible solutions, the other alternative is to move the private members into a pimpl and just have different versions of the private class for test and production (see https://wiki.qt.io/D-Pointer)
    3. The easiest and, if you ask me, more robust way to actually test it is to add a test db (a sqlite database file if you don't have a full fledged test db server) to your project and have the test program run off it rather than the production one. It's the only real way to actually test what will happen in production


  • Hey VRonin

    Thank you for your fast response and input.

    @VRonin said in Using Qt Test and private members:

    1. Why do you even have QSqlDatabase as a member? The fact that it is a pointer worries me even more

    What is wrong with this approach? Would it be better in your opinion to subclass QSqlDatabase?

    Regards
    Sebastian


  • Lifetime Qt Champion

    @Aslund said in Using Qt Test and private members:

    QSqlDatabase

    is a singleton and contains all databases you created. So, why do you need a pointer to a QSqlDatabase?
    See https://doc.qt.io/qt-5/qsqldatabase.html

    // Add database
    QSqlDatabase db = QSqlDatabase::addDatabase("QPSQL");
    db.setHostName("acidalia");
    db.setDatabaseName("customdb");
    db.setUserName("mojito");
    db.setPassword("J0a1m8");
    bool ok = db.open();
    ...
    // Here you get your database
    QSqlDatabase db = QSqlDatabase::database();
    


  • @jsulm

    Hey Jsulm

    Thank you for clearing it up. Makes sense now. I missed the fact that QSqlDatabase is a singleton. Rereading the documentation I can also see the following statement.

    Warning: It is highly recommended that you do not keep a copy of the QSqlDatabase around as a member of a class, as this will prevent the instance from being correctly cleaned up on shutdown. If you need to access an existing QSqlDatabase, it should be accessed with database(). If you chose to have a QSqlDatabase member variable, this needs to be deleted before the QCoreApplication instance is deleted, otherwise it may lead to undefined behavior.


Log in to reply