Fork me on GitHub

frequently asked questionsFAQ

What is TUT?

TUT is a small and portable unit test framework for C++. It’s so small that it fits into one header file. It’s so portable that it could be used on almost any C++ platform, including Windows, MacOS, Unices and embedded devices.

How is it different from C++Unit (boost::test, …)?

C++Unit, boost::test and other frameworks has similar goals, but there are some issues with many of them: * they require to use a library * tests depend on preprocessor macros * they often overloaded with features

TUT, in contrast, is located in header files only. All you should do is to include it into the test module. No linking at all.

TUT uses C++ template engine to dispatch calls to test methods. Therefore you shouldn’t even register methods s tests; template will do it for you automatically. As a result, the test code is more readable.

And finally, TUT is a minimal software. It only does what it’s designed for. It doesn’t integrate with MSDN or control production processes. It just runs tests.

Which compilers are supported?

Most modern compilers are supported. Some outdated compilers are unable to handle templates in TUT, alas.

Supported: * GNU GCC 2.95 * GNU GCC 3.x (both under unix and MinGW) * Borland 5.6 (Borland C++ Builder 6) * Intel C++ Compiler 6.x * Intel C++ Compiler 8.1 * Sun Studio 9: C++ 5.6 Compiler * Microsoft VC7 (Microsoft VS.NET 2003 and later) * Sun WorkShop 6 update 2 C++ 5.3 (probably, previous versions as well)

Unsupported: * Borland 5.5.x (Borland C++ Builder 5) * Microsoft VC6 (including SP5) * Microsoft VC7 (Microsoft VS.NET 2002) * C for AIX Compiler, Version 6 * KAI C++ Compiler * Portland Group Compiler, Version 5.2-4

If you use TUT with any other compiler or environment please let me know.

Some broken compiler/linker/platform combinations require to make methods ensure(), ensure_equals and fail() to be inline, and not in anonymous namespace. Try to change tut.h accordingly if you see “duplicate symbol ensure” or “ensure is not found” during linking stage.

Can we test private methods?

Alas.

First, from a pure theoretical POV, testing private methods is considered harmful as it exposes class internals, while traditional testing focuses on public interface only.

Second, it’s just plain impossible in C++ without making TUT a friend of tested class. It is strongly discouraged, since it makes actual implementation dependant on TUT internals. Don’t be surprised if things do not compile with next release.

If you really must, friend declaration should look like this:

// forward declaration is necessary
namespace tut
{
    template<typename T>
    class test_object;
}

class MyClass
{
    template<typename T>
    friend class tut::test_object;

    // code follows
}

On the other hand, most compilers do not change the ABI when moving private section around, so exposing all internals to TUT might be as simple as below. Your mileage may vary, though.

#define private public
#define protected public
#include "MyClass.h"

// test code follows

Can we use strings as test names, please?

No and yes. C++ template engine doesn’t support usage of run-time objects (and string is a run-time object) for specialization. Compile-time constants is the only way.

On the other hand, there is a method set_test_name(“a name”) which you can call in the beginning of a test to make it look prettier in the failed build report.

How about test fixtures (setUp/tearDown methods)?

To aquire resources before the test and to release them right after the test use constructor and destructor of the data structure:

// ...
struct complex_data 
{ 
    connection* con;
    complex_data() { con = db_pool.get_connection(); } 
    ~complex_data() { db_pool.release_connection(con); } 
};

template<> 
template<> 
void testobject::test<1>() 
{ 
    // ...
    con->commit();
}

Each test in the group from now on will have the connection initialized by constructor and released in destructor.

What would happen if the constructor throws an exception? TUT will treat it as if test itself failed with an exception. The test body won’t be executed and it will be reported as failed with exception. But the destructor of the data structure will be executed anyway!

An exception in the destructor is threated differently though. Reaching destruction phase means that the test itself has finished successfuly. In this case TUT marks the test with a warning status.

I’ve taken a look at the selftest code and it looks awful

Self tests are very special beasties, and actually you’ve seen two(!) TUT frameworks running one under control of another. The case is quite extreme. Regular TUT tests are very simple to read.

Is it possible to have more 50 tests per group?

Yes. A newly created group has a predefined set of dummy tests (i.e. test placeholders). By default, there are 50 tests in a group. To create a test group with a higher volume (e.g. when tests are generated by a script) provide a higher border of test group size when it is instantiated:

// test group with maximum 500 tests 
typedef test_group<huge_test_data,500> testgroup;

Note that your compiler would possibly need a command-line switch or pragma to enlarge the recursive instantiation depth. For g++, for example, you should specify –ftemplate-depth-501 to make example above compile. Please consult your compiler’s documentation.

I’ve used ensure_equals() method and compiler refused to build my code complaining that there is ambiguous overload for operator«.

One or both types you’ve provided to ensure_equals() have no operator « at all. Since the diagnostic message is built using std::stringstream, compiler needs the operator to format your objects. Either add the operator or use ensure() method (which doesn’t tell you the exact values the objects had, just the fact they were not equal).

What about segmentation faults in code being tested? What about deadlocks?

C++ Standard doesn’t specify what happens if the code references wrong address. Thus, segmentation fault processing is system and compiler dependent, and shall be handled differently for each system/compiler pair.

If you want TUT to react correctly to tests failures caused by segfaults, you must somehow convert hardware faults into C++ exceptions.

For Win32 TUT uses SEH. You need to specify -DTUT_USE_SEH at the test build time.

For unixes there is no standard way to convert SIGSEGV into an exception. Consult your platform/compiler documentation for possible ways to do that.

You may also use restartable wrapper defined in optional header tut_restartable.h. It runs the tests the same way as regular runner does, but also logs the progress. If a test crashes the test application, and then test application is started again, the wrapper will load last log record, and continue test execution from position after the crashed one.

Of course, this requires helper script that runs test application until all tests will be runned. The script might be is as simple as: <div class="CodeRay"> <div class="code"><pre> while true do ./restartable &amp;&amp; exit 0 done </pre></div> </div>

Directory examples/restartable contains a simple restartable test application.

This approach can be extended to support deadlocks in code. The script must be modified to automatically kill test application after specified period of time.

What is this multi-process testing mentioned in the summary?

It allows spawning child processes on platforms that support it. This is often needed when testing client/server applications. Using TUT, one can fork the main process and use ensure_* functions in both processes. Moreover, one can ensure that spawned processes exited, were killed etc.

TUT takes care of all necessary cleanup: all spawned processes are stopped after current test case finishes.

Where can I ask a question?

TUT has a small forum on SourceForge. Feel free to post your comments, questions and bug-reports there.