Cpp Unit Reflection

At my day-gig, a colleague wrote an in-house CppUnit that performs a little extra-linguistic magic to reflect.

At test compile time, we parse the source of any file called test*.cpp, looking for lines that say "^test[_a-zA-Z]*\b". Because one would have to be sloppy to write that into a well-formatted source file without it's the start of a test function, I have never seen this system miss one or hit a false positive.

Hence, we don't need to declare the Suite, inherit anything, add any method pointers to the Suite, or collate all Suites. The tool does this when we hit the Test Button.

Reading the docs to CppUnit, I don't see this feature. And I do see lots of elaborate kvetching about elaborate CPP macros or editor macros. This is an OrganizationalSmell? - ThreeStrikesAndYouAutomate. -- PhlIp

The "extra-linguistic magic", which I assume is a Perl script or something similar, is an example of a TestCollector. /C++, unfortunately, requires a TestCollector be implemented outside the language. Actually, so far as I know, Java TestCollector-es also need external scripts. CppUnit's fairly recently added test registry is a TestCollector that works inside the space of objects that have been linked, but which does not span different "compilation units", aka source or object files.

Legacy Reflection Thoughts

I added this to TestCaller.h just to simplify the addition of testmethods to a suite (of course your compiler needs to have reasonable template support):

 template <class Fixture> 
 TestCaller<Fixture> *test_newCaller(
	std::string name,
	void (Fixture::*f)()
	) {
  return new TestCaller<Fixture>(name,f);

#define TEST_NEWCALLER(f) test_newCaller((#f),(f))

Then I can use the following:

 Test *fm_WhateverTest::suite() {
  TestSuite *ts = new TestSuite;
  ts->addTest (TEST_NEWCALLER(testIterator));
  return ts;


I played around with CppUnit back six months or so ago, and wasn't wild about it. The stuff's all there, but I felt there was too much syntax, especially for my C++ newbie team (see XpAtArinc). Unit testing is so integral to the process, I wanted it to be absolutely painless to do, right from day one. So, I just liberated the basic concepts and implemented them my own weird way. My resulting framework makes tests via declarations like so:

 #include "Test.h"
 #include "BinaryFile?.h"

class cTestBinaryFile : public cTest { protected: void Run(); { // ...Body... } };

static cTestBinaryFile s_TestBinaryFile;

The static declaration adds the test to the master list. The list is used to display the entire set, so I can select one and run it, or all of them. Downside to my current arrangement is that I'd like to have full-scale tree structure to my tests, as they are harder to select once the list gets large.

I always take as full advantage as I can of the development environment. In this case (VC6), I use RunTimeTypeInformation, the full exception mechanism, and VC6's ability to readily leave a file out of a particular build configuration. All tests are in separate .cpp files from their test-ee, and they are simply left out of the compile in the release. -- MichaelHill

Of course, no sooner did I write this down than I became convinced that I couldn't live without tree structure. The new format is simpler than the old:

 DEFINE_SUITE(Files);  // define a new test suite named Files
 DEFINE_TEST(BinaryIO,Files)  // add BinaryIO to Files
 ...body of test...

This is of course a use of the forbidden pre-processor. In spite of the language-lawyers best efforts to reduce pre-processing in the C++ environment, there are still things you can't do without macros. I am very happy with the result, and my testing display now shows a nice tree structure with open nodes leading to failures and successes all compressed. Of course, it still doesn't have proper fixtures. But, to be honest with you, I have never felt the need for them. I prefer to set up the test in code. -- MichaelHill

Michael, I just started looking at CppUnit recently, and had the same reaction to the fixtures. I've been thinking of doing something very much like what you describe here, for all the same reasons. In fact, I don't really see why most test cases couldn't be coded as a simple function, with local variables providing anything that the fixture would. I also like some of what RobertDiFalco describes in CppUtxOverview, however, because I anticipate having (eventually) a very large set of unit tests in our program. I'm going to go play around with these ideas a bit now. -- DanMuller

CppUnitLite, NanoCppUnit, etc. put a bullet straight through this problem with the TEST_(suite, case) macro.


View edit of January 25, 2006 or FindPage with title or text search