Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use cppunit just like junit --- two mains

Tags:

c++

cppunit

I know that the unit test for Java is very simple. We just need use JUnit and run test classes as JUnit test.

Now I'm working with C++ and I find a test library: cppunit.

It seems that I need to run my test with a specific function main. However, a cpp project can have ONLY ONE main.

What should I do? I have to switch mains when I do my test and when I run my project?

like image 633
Yves Avatar asked Dec 03 '25 22:12

Yves


1 Answers

What should I do? I have to switch mains when I do my test and when I run my project?

You should separate the code to test into a library project, that can be linked from your target application and the unit test runner.

Then have two more projects providing a main() function:

  • one for the target app, that just forwards main() implementation to a call of a MyTargetApp class member function, e.g. MyTargetApp::run()
  • one for the unit testing, that calls a TestRunner, and contains all of the test suite and fixture classes (including these for the MyTargetApp).

The target application project can be configured without linking against the cppunit library and your test suite/fixture implementations (which will certainly reduce the final artifacts footprint).


However, a cpp project can have ONLY ONE main.

Another option is to use just one project with a narrow main() function that can be compiled using a conditional preprocessor statement (as from their example on the TestRunner class):

 #ifdef TESTING
 int runUnitTests(int argc, char* argv[]);
 #endif

 int main(int argc, char* argv[]) {

 #ifdef TESTING
     // run the unit tests
     // -----------------------------------------------------------------
     return runUnitTests(argc,argv);
 #else
     // run the application
     // -----------------------------------------------------------------
     MyTargetApp app;
     return app.run(argc,argv);
 #endif

 #ifdef TESTING
 int runUnitTests(int argc, char* argv[]) {
   std::string testPath = (argc > 1) ? std::string(argv[1]) : "";

   // Create the event manager and test controller
   CppUnit::TestResult controller;

   // Add a listener that colllects test result
   CppUnit::TestResultCollector result;
   controller.addListener( &result );        

   // Add a listener that print dots as test run.
   CppUnit::TextTestProgressListener progress;
   controller.addListener( &progress );      

   // Add the top suite to the test runner
   CppUnit::TestRunner runner;
   runner.addTest( CppUnit::TestFactoryRegistry::getRegistry().makeTest() );   
   try {
     std::cout << "Running "  <<  testPath;
     runner.run( controller, testPath );

     std::cerr << std::endl;

     // Print test in a compiler compatible format.
     CppUnit::CompilerOutputter outputter( &result, std::cerr );
     outputter.write();                      
   }
   catch ( std::invalid_argument &e ) {
     // Test path not resolved
     std::cerr  <<  std::endl  
                <<  "ERROR: "  <<  e.what()
                << std::endl;
     return 0;
   }         

   return result.wasSuccessful() ? 0 : 1;
 }
 #endif

Then have 2 different project configurations, one that defines TESTING and one without.

One disadvantage of this solution is though, you'll get all the unit test suites and fixtures left in your program, because cppunit macros will register and instantiate them automatically, regardless if the will be called from the execution path.

like image 71
πάντα ῥεῖ Avatar answered Dec 05 '25 11:12

πάντα ῥεῖ



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!