Search code examples
c++visual-studio-2012catch-unit-test

Redefined Catch unit tests


I'm testing a huge piece of software and would like to use Catch for this task. I'm using the "single include" version 1.9, integrating it in Visual Studio 2012 update 4 and using C++04 standard.

As you will see below, I use three ".cpp" files. Each of them reference:

  • a include file providing "abstraction" macros (eg. #define Assert(x) REQUIRE(x));
  • a utility file providing... utilities for the test;
  • the specific test target include files;
  • some "using namespace" statement, all cpp files "using" the same namespace;
  • the actual tests, written with the macros (eg. Assert(2 == getNumber())).

More details on the files content below.

This configuration works, but one of the test file is growing bigger by the day and I would like to split it in 3, or more. Now, say that I do the following:

  • take part of the content of a test test.cpp and move it in a new file test2.cpp;
  • add the same includes and defines to make it compile;
  • include the new file in my main

this error pops up when I run the tests:

=============================
No tests ran
error: TEST_CASE( "test 2" ) already defined.
    First seen at c:\tests\catchtest2\catchtest2\test2.cpp(3)
    Redefined at c:\tests\catchtest2\catchtest2\test2.cpp(3)

where test2.cpp is the new file. If I move the content back to test.cpp it all works, but working with tests thousands of lines long is almost harder than working on the project itself, and the dimension could grow 3, 4 times bigger still. Is there a way to split the tests in multiple files?

-- NOTES --

I reckon including Catch in a header and using the including header instead of catch.cpp directly is not a good idea, but I successfully used this configuration with 3 (exactly 3) included .cpp test files, and am unable to use this with 4 files.

I remember reading that it was somehow related to the line at which the components were defined, but I can also move the code so that the test cases are defined at different lines and the behaviour doesn't change.

I also tried to "clean and rebuild", because it may well be that dirty data is kept in the compiler / linker's caches, but to no avail.

I couldn't create an actual MWE right now, so I gave you a sketch of the test setup as accurate as I thought it could be needed. I'm more than willing to provide additional details or try and build an actual MWE and share it.

Any idea is appreciated!


My "working" code looks like this:

main.cpp

#define CATCH_CONFIG_RUNNER
#include "catch.hpp"
#include "test1.cpp"
#include "test2.cpp"
#include "test3.cpp"

int main( int argc, char* argv[] )
{
    cleanDir("c:\\temp");
    init (argv);
    int result = Catch::Session().run( argc, argv );
    return ( result < 0xff ? result : 0xff );
}

test1.cpp

#include "unitTestSuite.h"
#include "utils.h"
#include "systemundertest.h"

using namespace system::under::test;

my_test_case("test 1") {
    my_section("does X") {
        // tests...
    }
}

my_test_case("test 2") {
    my_section("does Y") {
        // tests...
    }
}

unitTestSuite.h

#ifndef UNIT_TEST_SUITE
#define UNIT_TEST_SUITE 1

#include "catch.hpp"
#define my_test_case(x) TEST_CASE("Testing: " x)
... // here is also a namespace with some unit test specific utils
#endif

utils.h

#ifndef _UTILS_
#define _UTILS_
// some global variables declared here and defined in utils.cpp
// template functions defined in the header
// non-template functions defined in utils.cpp
// a test generation namespace with some template functions and some non-template functions defined in utils.cpp
#endif

After the "split":

test1.cpp

#include "unitTestSuite.h"
#include "utils.h"
#include "systemundertest.h"

using namespace system::under::test;

my_test_case("test 1") {
    my_section("does X") {
        // tests...
    }
}

test1.2.cpp

#include "unitTestSuite.h"
#include "utils.h"
#include "systemundertest.h"

using namespace system::under::test;

my_test_case("test 2") {
    my_section("does Y") {
        // tests...
    }
}

main.cpp

#define CATCH_CONFIG_RUNNER
#include "catch.hpp"
#include "test1.cpp"
#include "test1.2.cpp"
#include "test2.cpp"
#include "test3.cpp"

int main( int argc, char* argv[] )
{
    cleanDir("c:\\temp");
    init (argv);
    int result = Catch::Session().run( argc, argv );
    return ( result < 0xff ? result : 0xff );
}

program output:

=============================
No tests ran
error: TEST_CASE( "test 2" ) already defined.
    First seen at c:\tests\catchtest2\catchtest2\test1.2.cpp(3)
    Redefined at c:\tests\catchtest2\catchtest2\test1.2.cpp(3)

Solution

  • Don’t include the cpp files, just add them to the project. Your main.cpp file only needs the first two lines (a define and an include).