1

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)
phagio
  • 196
  • 1
  • 14
  • Why are you including cpp files? – jbcoe Nov 21 '17 at 20:04
  • It seems this is how catch manages tests.. i tried including headers and defining tests in separate cpp files, but got 8 assertions running instead of 1750 so i guess something went wrong ^^" – phagio Nov 21 '17 at 21:13
  • I think your main.cpp needs only the first two lines. You can link the object files from the test cpp’s into the same executable as that built with main.cpp. As a rule of thumb, if you include a cpp file you’re doing something odd. – jbcoe Nov 21 '17 at 21:31
  • Hmm, all catch examples use this pattern so I thought it was mandatory for the "catch magic" to happen. I will try to remove the cpp references and get back to this thread, thank you for the suggestion :) – phagio Nov 21 '17 at 21:53
  • Do you have a reference for the examples? I’m quite happy to be re-educated if needs be. – jbcoe Nov 21 '17 at 22:04
  • For catch2 the help file at "scaling up": https://github.com/catchorg/Catch2/blob/master/docs/tutorial.md#scaling-up recommends to avoid putting tests in headers and talks about "using as many cpp files as needed", but it actually says nothing about them having to be included. – phagio Nov 22 '17 at 07:01
  • @jbcoe, you were right: the documentation examples show that it's not needed to include cpp files, and I successfully split files without including them. The odd thing is, I had the "8 assertions" problem until I created new source files and moved the code there. I guess it's something related to some strange VisualStudio cache, or the like. If you post the "don't include cpp files, just add them to the project" proposal as an answer I will gladly accept it! – phagio Nov 22 '17 at 11:34

1 Answers1

4

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).

jbcoe
  • 3,611
  • 1
  • 30
  • 45