I’d like to describe options I often use in my Qt projects.

OBJECTS_DIR = build
DESTDIR = dist

I don’t use shadow build and this keeps all object files in build/ subfolder making it easier to browse through the root folder. With second option my executables end up in the dist/ subfolder.

VERSION = 0.1
DEFINES += APP_VERSION=\\\"$$VERSION\\\"

This defines version of the project and makes it available as string APP_VERSION in sources. And yes, that amount of backslashes is required for it to work as string. By the way I use it in the following piece of code I put into my main() functions in order for everything to work well:

Q_INIT_RESOURCE(resources);
qsrand(qHash(QTime::currentTime().toString("hmsz")));

QApplication app(argc, argv);
QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));

app.setApplicationName(QObject::tr("Application Name"));
app.setApplicationVersion(QObject::tr(APP_VERSION));
app.setOrganizationName(QObject::tr("Xilexio"));

I use the last 3 variables through qApp macro later in my applications, usually to display appropriate window title.

win32 {
    LIBS += -Llib/win32
}

unix {
    LIBS += -Llib/unix
}

Example how to use conditionals on win32 and unix variables (defined automatically on Windows and Unix systems respectively) in order to link with appropriate libraries. This works if you provide library binaries together with code and put them to different directory for each system. The same conditionals can be used together with “CONFIG+=variableName” put into Project > Build Settings > Build steps > qmake step > Additional arguments. I use them to add test builds that way.

CONFIG(debug, debug|release) {
    CONFIG += console
}

Another conditional, this time switched only for debug build. We need to add “console” to config in order for information from qDebug and others to appear. That switch takes care of it. For release conditional simply replace “debug” with “release” in the first argument.

INCLUDEPATH += lib/include

This adds a space-separated list of folders for global #includes. They are passed to g++ compiler with -I and are also used for automatic code completion.

LIBS += -lz

Arguments for linking with libraries passed to the compiler. Put your -L and -l arguments here. Note: the code above searches for libz.a, z.a, libz.dll and z.dll in case of g++.

TARGET = great-program

Name of your executable.

build
debug
dist
release
Makefile*
*.pro.user
ui_*
moc_*
qrc_*
*.rc
object_script.*

Not really an option, but this is my generic .gitignore file I use in my Qt projects. Those are all generated or machine-dependent files and shouldn’t be checked into a git repository.

Qt comes with QtTest library, which lets you write your own test suites for internal and GUI components. However, its usage together with your application in an easy to maintain way is not so obvious. In this tutorial I’ll focus more on framework and ease of usage and less on how to write contents of tests themselves. There is already a tutorial on how to write QtTest unit tests. I’m using Qt 4.8 for this tutorial, but those methods and concepts can be used in Qt 5 too.

Some code to test

I created an example project, which is a simple math expressions parser with GUI. I’m sharing it under Public Domain license on bitbucket, so use is as you please. There are three non-GUI classes there:

  • Token – class representing a single entity in math expressions – a number or an operator (+, -, *, /),
  • MathTokenier – class used to split a string into tokens while validating input,
  • MathParser – class used to parse and compute expression consisting of sequence of tokens.

Writing test suites

Having some decent chunk of code, we can now move on to testing it. Tests are grouped into test suites. Test suite is represented by a normal QObject class with test functions being her slots. There’s a special naming convention used here:

  • Tests have “test” prefix of their method name,
  • initTestCase() and cleanupTestCase() are methods called before and after execution of the whole test suite,
  • init() and cleanup() are methods called before and after execution of each test in the suite.

Structure is as below:

#include <QtTest>

class TestSomething : public QObject {
    Q_OBJECT

private slots:
    // functions executed by QtTest before and after test suite
    void initTestCase();
    void cleanupTestCase();

    // functions executed by QtTest before and after each test
    void init();
    void cleanup();

    // test functions - all functions prefixed with "test" will be ran as tests
    void testSomething();
};

Any function not conforming to those name conventions will be just ignored and not ran as test. So we can safely create helper functions. I’d like to note that this whole mechanism work well thanks to QObject’s meta properties which lets you list and access all your slots dynamically (and much more).

Lets create such a test suite in test/ folder (or some other location). It’s a good idea to write some stubs at the beginning to see if everything works well. So lets do this:

void TestTriangleIntegral::testStubPass() {
    QVERIFY(true);
}

void TestTriangleIntegral::testStubFail() {
    QVERIFY(false);
}

After setting everything up well, two messages should pop out after running those tests:

PASS   : TestSomething::testStubPass()
FAIL!  : TestSomething::testStubFail() 'false' returned FALSE.

Running test suites

QtTest library is used by making a separate executable that runs your tests. If you’d do this by creating another project, you’d have to maintain two lists of source files, libraries, flags etc. I’ll describe the approach I’ve taken to avoid that.

The default way is to use QTEST_MAIN macro, but that lets you use just one test suite per executable. Lets use another approach by creating a main() function for tests in test/main.cpp in the following fashion:

#include <QtTest>
#include "testsuite1.h"
#include "testsuite2.h"

int main(int argc, char** argv) {
    QApplication app(argc, argv);
    QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));

    TestSuite1 testSuite1;
    TestSuite2 testSuite2;
    // multiple test suites can be ran like this
    return QTest::qExec(&testSuite1, argc, argv) |
            QTest::qExec(&testSuite2, argc, argv);
}

Note usage of “|” instead of “||”. This is in order to run all tests, even if one of test suites failed.

That’d be enough to run a test suite if it was a standalone application. But since we don’t want to maintain two applications, we’ll share the build between them.

Lets create a new Build Configuration to produce unit tests executable while also including to the build all code used in original application. Go to Projects > Build Settings and duplicate your debug configuration naming the new one “Test”. Then go to Build Steps, select qmake step and add additional argument “CONFIG+=test”. “Additional arguments” is a place in which you can define some additional parameters for your build. We’ll be using this together with conditionals in Qt project file (.pro) to create test build.
qt-config-test
Note: this step has to be repeated for each checkout of your project, as those settings are stored in “.pro.user” file (which shouldn’t be checked in as it contains machine-specific build information).

QtTest application differs from our application only by using different main function and having additional test suite classes. If you didn’t put much code into your main function (which should have been the case), you should be fine with just removing it from test build. You can use the “test” configuration argument defined earlier to incorporate that. Lets create the test build by:

  • adding QtTest library,
  • renaming our target executable to one with test name (optional),
  • removing original main.cpp file (in order to avoid conflicts),
  • adding sources of our test suites.

Assuming main.cpp contains your original main function, test/main.cpp contains main function for tests and test/testSuite* contain test suites, you can use following code:

test {
    message(Test build)
    QT += testlib
    TARGET = UnitTests

    SOURCES -= main.cpp

    HEADERS += test/testSuite1.h \
        test/testSuite2.h

    SOURCES += test/main.cpp \
        test/testSuite1.cpp \
        test/testSuite2.cpp
} else {
    message(Normal build)
}

In case of normal build it only displays message. But in case of test (CONFIG+=test) build, it also does changes mentioned above.

Writing test methods

Content of those tests is just like normal test cases – initialize some data, run tested code and check if everything is okay. I won’t go into details – QtTest tutorial elaborates enough on them. Just remember to browse through available macros and use QVERIFY/QVERIFY2 and QCOMPARE instead of Q_ASSERTs. See test/testMathTokenizer.cpp in my example project for examples of test methods themselves. If you want to write more exhaustive tests, have a look at Qt’s data-driven tests. There are also GUI tests, but those work well mainly on widgets, as your main window usually has private access to UI elements.

This setup allows for development in which you often write tests and run them, but is not quite as convenient as to hit some key combination to run your tests and display red/green. Also switching between builds (Debug/Test) is required if you want to alternate between running tests and application. So test-driven development is possible, although requires more work than in other libraries/languages.

I chose to use VTK 6.0.0 library in my project in order to visualize solution of system of partial differential equations in my Qt 4 application. By the way, I’m solving PDEs using getfem++.

I had to compile VTK first though. It wasn’t quite as complex as compiling getfem++, but still required some tweaking for my non-CMake based project. You can find compiled VTK binaries in my vtk bitbucket repository.

I was building this library on Windows 7 with GNUStep’s mingw32 with g++ 4.6.1.

VTK library build is CMake based. The good news is that the library build itself works well. The bad news is that using it in your non-CMake aplication requires some care. To build VTK first install CMake if you haven’t already done so and make sure it’s in your PATH.
The build I made was with additional Qt and Views modules, so I also had to include Qt libraries in PATH:

export PATH="/C/Qt/4.8.4/bin:/C/Program Files (x86)/CMake 2.8/bin:$PATH"

After unzipping the code I ran CMake from command line including my build options and using MSYS makefiles (normal ones used in GNUStep’s makes):

cmake -D BUILD_EXAMPLES=1 -D BUILD_SHARED_LIBS=1 -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/home/xilexio/vtk -D VTK_Group_Qt=1 -G "MSYS Makefiles" .
make
make install

That created VTK release library. Note that VTK release library uses Qt Release libraries. For debug VTK library, I changed CMAKE_BUILD_TYPE to Debug.

The problems with VTK arrive with its usage in non-CMake. I use Qt Creator and its project file (.pro) for building my application. There are two things to consider here. First – building and running with appropriate VTK libraries. For VTK’s Qt module to work, you have to use release VTK with release Qt and debug VTK with debug Qt. Sounds easy, but requires configuration in two places:

  • You have to include a condition in your project file to link with appropriate VTK version (here we additionally only set it for Windows):
    win32 {
        CONFIG(debug, debug|release) {
            LIBS += -Llib/vtk/release
        } else {
            LIBS += -Llib/vtk/debug
        }
    }
  • You have to run the application with appropriate VTK libraries in PATH. In Qt Creator go to Projects > Run and create two Run Configurations – debug and release. In Run Environment set the PATH to contain only one version of VTK libraries (debug or release). Another option could be renaming all VTK libraries, for example by appending “d” to file name, but I haven’t tested that.

If you’ll forget about those steps, you’ll get following error:

QWidget: Must construct a QApplication before a QPaintDevice

The cause for this error is usually using two different Qt libraries (in our case both debug and release). So, make sure to attach proper set of Qt and VTK libraries when deploying the application.

Second thing to remember is supplying appropriate defines to VTK headers. As stated here, if you’re not using CMake build, you have to set those defines yourself. You must define two variables before including any VTK header. I tried adding defines to my project file:

DEFINES += vtkRenderingVolume_AUTOINIT=...

but in the end I wasn’t able to get a good amount of backslashes and quotes to make it work. So I had to go with a precompiled header:

PRECOMPILED_HEADER = pch.h

and paste default options in it:

#ifndef PCH_H
#define PCH_H
#define vtkRenderingCore_AUTOINIT 4(vtkInteractionStyle,vtkRenderingFreeType,vtkRenderingFreeTypeOpenGL,vtkRenderingOpenGL)
#define vtkRenderingVolume_AUTOINIT 1(vtkRenderingVolumeOpenGL)
#endif // PCH_H

If you’ll forget about this step, program will crash once you actually try to use the library (in my case after clicking QVTKWidget window) giving the following error:

Generic Warning: In c:/GNUstep/msys/1.0/home/Xilexio/vtksrc2/VTK6.0.0/Rendering/Core/vtkRenderWindow.cxx, line 35
Error: no override found for 'vtkRenderWindow'.

With all that configuration VTK becomes usable in Qt project. However, there’s one thing to note if you’re deploying your application. For some reason a hardcoded directory path VTK_MATERIALS_DIRS generated during installation exists in vtkRenderingOpenGLConfigure.h. Apparently it’s used to locate some files with vtkXMLShader::LocateFile (and maybe in other places too). My guess is that as long as you don’t use magical functions like “find my file without me specifying root directory”, it should work on other machines too.

Here you can find sources of a simple Qt 4.8 application that takes XML input and can do the following:

  • check its validity according to given XML Schema
  • make an XSLT transformation on it
  • check validity of XSLT transformation output according to given XML Schema

The purpose of this simple application was to test how much of XML Schema and XSLT functionalities were implemented in Qt 4.8 and to help in debugging XML Schema and XSLT taking into account how much of it is supported. The result was that XML Schema 1.0 is supported pretty well, but XSLT isn’t implemented well enough for production neither in XSLT 1.0 nor XSLT 2.0 standard.

As stated here, Qt 4.8 implements XML Schema 1.0. One can read here that Qt 4.8 has only experimental support of XSLT 2.0. There’s also a list of unsupported features over there. Here are some things I found out:

  • for-each-group doesn’t really work.
  • for-each doesn’t work on a sequence of atomic types. For example, you can’t do that:
    <xsl:for-each select="distinct-values(/lib:record/lib:name)">

    The trick I used to bypass it in this case was simply by getting those values as nodes:

    <xsl:for-each select="for $n in distinct-values(/lib:record/lib:name) return /lib:record[lib:name=$n][1]/lib:name">
  • Sequence of nodes can’t be passed in xsl:call-template parameters. To bypass that, I simply passed some atomic type that would identify the sequence and recreated it in the called template.
  • xsl:key doesn’t work (as stated in the documentation).

Generally, lack of support of many features can be bypassed without increasing the problem complexity by using weird tricks. As in example above, it’s always better to iterate over distinct-values (XSLT 2.0) and take them as nodes from the file instead of using dreadful square-time constructions like not(preceding-simbling::…) (which probably would be the case for XSLT 1.0 without xsl:key support). Though, I wouldn’t recommend using Qt 4.8 XSLT in real production unless the XSLT is really simple.