I am starting with C++ unit tests using CppUnit. The goal I am trying to achieve is to run all my test suites on a single main file (and function). Let me explain:
Let's say we have two classes with test for two C++ classes I have designed:
#ifndef FIRSTCLASSTEST_H
#define FIRSTCLASSTEST_H
class FirstClassTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE( FirstClassTest );
CPPUNIT_TEST( testConstructor );
CPPUNIT_TEST_SUITE_END();
public:
void setUp(void);
void tearDown(void);
protected:
void testConstructor(void);
};
#endif
And let the other class be similar:
#ifndef SECONDCLASSTEST_H
#define SECONDCLASSTEST_H
class SecondClassTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE( SecondClassTest );
CPPUNIT_TEST( testConstructor );
CPPUNIT_TEST_SUITE_END();
public:
void setUp(void);
void tearDown(void);
protected:
void testConstructor(void);
};
#endif
And the cpp files look similar to:
#include "FirstClassTest.h"
CPPUNIT_REGISTRY_ADD_TO_DEFAULT( FirstClassTest );
void FirstClassTest::setUp(){
//setup...
}
void FirstClassTest::tearDown(){
//teardown...
}
void FirstClassTest::testConstructor(){
//some asserts
}
After these files (Which work properly individually), I want to create a unique file to run all my registered suites. Let's say my main test runner is AllTest.cpp:
#include <cppunit/TestResult.h>
#include <cppunit/TestResultCollector.h>
#include <cppunit/BriefTestProgressListener.h>
#include <cppunit/TestRunner.h>
#include <cppunit/CompilerOutputter.h>
#include <cppunit/extensions/HelperMacros.h>
//Include Test classes here
#include "FirstClassTest.cpp"
#include "SecondClassTest.cpp"
int main()
{
// informs test-listener about testresults
CPPUNIT_NS::TestResult testresult;
// register listener for collecting the test-results
CPPUNIT_NS::TestResultCollector collectedresults;
testresult.addListener (&collectedresults);
// register listener for per-test progress output
CPPUNIT_NS::BriefTestProgressListener progress;
testresult.addListener (&progress);
// insert test-suite at test-runner by registry
CPPUNIT_NS::TestRunner testrunner;
testrunner.addTest (CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest ());
testrunner.run(testresult);
// output results in compiler-format
CPPUNIT_NS::CompilerOutputter compileroutputter(&collectedresults, std::cerr);
compileroutputter.write ();
// return 0 if tests were successful
return collectedresults.wasSuccessful() ? 0 : 1;
}
But this does not work. How can I achieve the desired behavior? I have checked the docs: http://cppunit.sourceforge.net/doc/cvs/class_auto_register_suite.html but without success.
I suspect the main problem is in the AllTests.cpp and I am not adding the suites properly to the registry or to the testRunner.
Any help would be appreciated. Cheers.
SOLUTION EDIT: Finally, and thanks to the examples and advices provided by @moggi, I have been able to resolve my problem. I have removed any CPP_UNIT_SUITE_REGISTRATION
from my cpp files and I have modified the AllTest.cpp main function to be like this:
int main()
{
// informs test-listener about testresults
CPPUNIT_NS::TestResult testresult;
// register listener for collecting the test-results
CPPUNIT_NS::TestResultCollector collectedresults;
testresult.addListener (&collectedresults);
// register listener for per-test progress output
CPPUNIT_NS::BriefTestProgressListener progress;
testresult.addListener (&progress);
// insert test-suite at test-runner by registry
CPPUNIT_NS::TestRunner testrunner;
// MODIFIED PART, TEST SUITES ADDED MANUALLY
testrunner.addTest( FirstClassTest::suite() );
testrunner.addTest( SecondClassTest::suite() );
testrunner.run(testresult);
// output results in compiler-format
CPPUNIT_NS::CompilerOutputter compileroutputter(&collectedresults, std::cerr);
compileroutputter.write ();
// return 0 if tests were successful
return collectedresults.wasSuccessful() ? 0 : 1;
}
So there are basically two solutions that you use.
Link everything together and register your test suite with CPPUNIT_TEST_SUITE_REGISTRATION
and be happy. This requires the test code and your AllTest.cpp to be linked together.
Dynamically load your tests during runtime and use CPPUNIT_PLUGIN_IMPLEMENT
and also register with CPPUNIT_TEST_SUITE_REGISTRATION
.
The advantage of the first approach is that it is simple and you don't need to worry too much. Of course this simplicity comes with the price that if you want to use the code from AllTest.cpp for several independent tests that are not in separate binaries/libraries you need to link AllTest.cpp into all of them. More information about the CPPUNIT_TEST_SUITE_REGISTRATION can be found at the Creating TestSuite page in the documentation
To implement this approach in your code add to your cpp file the following for each test suite:
CPPUNIT_TEST_SUITE_REGISTRATION(FirstClassTest);
Obviously replace FirstClassTest with the test suite name that you used in CPPUNIT_TEST_SUITE
.
The second approach is a bit more complicated but allows to have one test binary and dynamically load the library with the test code during runtime. This allows e.g. to build several independent tests that can be run in parallel with the test runner being shared. More information for this approach can be found at the cppunit documentation for the PluginIn approach