How to structure project while unit-testing Qt app by QTestLib
Asked Answered
C

4

42

I got my Qt project and I'm using Qt Creator. I want to unit-test all my code.
However I'm quite new at QTestLib framework but everyone recommended it for testing Qt-based source. Now I'm a little confused how to structure test project with app project.

  1. Can I put all source and testing code in same project? If so, how could I manage them? I didn't find any option that let me start app or start test in one project.
  2. If I put app source and testing code in separate projects, the testing project will reference app project, that's not quite convenient.
  3. For lots for classes required to be tested, how do I manage testing code?

How do you guys manage testing code in such a situation? Thanks.

Craw answered 28/8, 2012 at 7:54 Comment(4)
Sure. @UmNyobe, I finally deployed source and testing code in separate projects. The test project referenced same sources by pri file with relative path.Craw
if you give clear description of what you have done, you get my bounty :DMaladminister
@UmNyobe, sorry for late reply, just check my post belowCraw
Any more new answers based on Cmake or QT 6 ?Moquette
C
19

First structure source like below:

MyApp
MyAppUnitTest

Under MyApp project, use a MyAppSrc.pri to locate source files:

SOURCES += \
    ../../../framework/src/myapp.cpp \
    ../../../framework/src/mycontrol.cpp

HEADERS += \
    ../../../framework/inc/myapp.h \
    ../../../framework/inc/mycontrol.h

INCLUDEPATH += ../../../framework/extlibs

Include this .pri in MyApp.pro like:

include(MyAppSrc.pri)

Then structure the testing project exactly like the main project, with one extra include in MyAppUnitTest.pro:

include(MyAppUnitTestSrc.pri)
include(../MyApp/MyAppSrc.pri)
Craw answered 25/12, 2012 at 2:46 Comment(1)
With this approach, does the source code get compiled twice (once for MyApp and once for MyAppUnitTest)?Bemuse
I
17

I use this approach: http://xilexio.org/?p=125

Namely, place a test config in the single .pro file that builds everything. File hierarchy:

myproject.pro
src/
    Example1.cpp
    Example2.cpp
    Example1.h
    Example2.h
test/
    ExampleTest.cpp
    ExampleTest.h

myproject.pro file:

QT += #needed modules

CONFIG += qt c++11

HEADERS += \
    src/Example1.h \
    src/Example2.h

SOURCES += \
    src/Example1.h \
    src/Example2.h

test{
    message(Configuring test build...)

    TEMPLATE = app
    TARGET = myapptests

    QT += testlib

    HEADERS += \
        test/ExampleTest.h

    SOURCES += \
        test/ExampleTest.cpp
}
else{
    TEMPLATE = lib
    TARGET = myapp

    CONFIG += plugin

    TARGET = $$qtLibraryTarget($$TARGET)
}

In my example, I'm building a plugin library, but the method should work for an app as well. In the case of an app, it is likely that SOURCES -= src/main.cpp is needed under the else clause, plugin libraries don't have it. If this is not done, the main() of the app will clash with the main() of the unit tests.

ExampleTest.cpp looks like the following:

#include "ExampleTest.h"

void ExampleTest::exampleTest(){
    //Do the tests
}

QTEST_MAIN(ExampleTest)

ExampleTest.h looks like the following:

#include <QtTest/QtTest>

class ExampleTest : public QObject {
Q_OBJECT

private slots:
    void exampleTest();
};

To build the project tests, in a separate directory than the regular build, run:

qmake path/to/myproject.pro "CONFIG += test"
Ida answered 29/4, 2016 at 9:25 Comment(1)
So, how do i make qmake fall into that test {Configuring test build...} ... case?Caffrey
F
9

I like the other answers but I would like to also give some feedback how we do this at the company I currently work for:

  1. Create a subdirs project (this will be the top-level project that will manage ALL including your library project or whatever you want to test)

    +-----MyProject (top-level subdirs)
    
  2. Add your library projects as a sub-project

    +-----MyProject (top-level subdirs)
              |
              +-----Library (library project, UI project etc.)
    
  3. Add another subdirs projects (for the tests)

    +-----MyProject (top-level subdirs)
              |
              +-----Library (library project, UI project etc.)
              |
              +-----Tests (subdirs for tests)
    
  4. Create a QUnitTest project an add it to the testing subdirs project

    +-----MyProject (subdirs)
              |
              +-----Library (library project, UI project etc.)
              |
              +-----Tests (subdirs for tests)
                      |
                      +----- TestA (QUnitTest project for testing feature A)
    
  5. Add as many tests as you see fit

             ...
              |
              +-----Tests (subdirs for test)
                      |
                      +----- TestA (QUnitTest project for testing feature A)
                      |
                      +----- TestB (QUnitTest project for testing feature B)
                      |
                      +----- TestC (QUnitTest project for testing feature C)
                      |
                     ...
                      |
                      +----- TestZ (QUnitTest project for testing feature Z)
    

If you need to group test in groups you can also use subdirs to do that. subdirs also ensures creating of real directories in your file system. If you want to avoid too much subdirsing you can group the tests in folders that you have created on your own in your filesystem inside the Tests project folder.

Beside that I would also recommend to add a subdirs for template projects.

+-----MyProject (subdirs)
          |
          +-----Library (library project, UI project etc.)
          |
          +-----Tests (subdirs for tests)
          |           |
          |          ...
          |
          +-----Templates (subdirs for template projects
                      |
                      +----- TemplateA (template project for feature A)
                      |
                      +----- TemplateB (template project for feature B)
                      |
                      +----- TemplateAB (template project for feature A and B together)
                      |
                     ...
                      |
                      +----- TemplateZ (template project for feature Z)

This is of course based on your library's functionality. With template projects I mean custom widgets etc. that link against your library and expose selectively (or all) of its functionality in the way it's supposed to appear to the user. For example if you have a library that manages various camera devices you can create a template project for each camera device thus allowing for the users of your library to just copy-paste the specific template project and expand it or at least see how the integration of your library is supposed to happen in general. This allows reducing the documentation and at the same time giving nice self-contained examples that should reduce the development time that is otherwise spent in figuring out how the integration and usage of the library works (you can say it's sort of a set of Hello World projects :)). Last but not least you can outline solutions for different use-cases.

Florina answered 2/11, 2016 at 12:40 Comment(0)
O
3

I use Qt Creator by CMake instead of qmake to build my Qt project.

Basically I have two folders:

src
tests

Each test is a program in itself testing a class. The app to be tested is compiled as a library.. You compile all your sources in the folder src as a library.

// ClassTest.cpp
#include "ClassTest.h"
#include "Class2Test.h" // Class of the app

#include <QtTest/QtTest>

ClassTest::ClassTest( QObject* parent )
    : QObject(parent)
{ 
}

QTEST_MAIN( ClassTest )
#include "ClassTest.moc"

You just have to link your lib to your test executable.

Example:

in the src folder CMakeLists.txt example

add_library( MyAPP
    SHARED
    Class2Test.cpp
)
target_link_libraries( MyAPP
    ${QT_LIBRARIES}
)

in the tests folder CMakeLists.txt example, for each test.

qt4_automoc( ${test_src} )
add_executable( ${test_name} ${test_src} )
target_link_libraries( ${test_name}
    MyAPP
    ${QT_LIBRARIES}
    ${QT_QTTEST_LIBRARY}
)

It is still in the same project but you can add a flag to let the user compile the test or not. It is clean because the app stays untouched and it allows you to test each class of your app.

Okelley answered 21/12, 2012 at 23:56 Comment(1)
a bit hard to read because of naming. What is a testclass and what is a class to test?Kure

© 2022 - 2024 — McMap. All rights reserved.