views:

65

answers:

3

So, imagine we have a class like this

class Testee
{
public:
   void Func()
private:
   void auxFunc()
};

and we want to do white-box unit-testing on it. Which do you think is a better approach? To declare the tester class a friend of the testee class? Or use the preprocessor like this:

  class Testee
    {
    public:
       void Func()
#ifndef UNITTEST_SYMBOL
    private:
#elif
    public:
#endif
       void auxFunc()
    };

and later in the testing file

#define UNITTEST_SYMBOL
#include "Testee.h"
#undef UNITTEST_SYMBOL

So, again, which do you think is a better approach? Or maybe you could suggest another approach. Thanks in advance.

+1  A: 

How about:

#ifndef UNITTEST_SYMBOL
#define semiprivate private 
#else
#define semiprivate public
#endif

and declare your class like:

  class Testee
    {
    public:
       void Func()
    semiprivate:
       void auxFunc()
    };

or even, if you're daring enough, do #define private public when testing.

Lie Ryan
So, I guess you are in favor of the preprocessor. Could you please provide some arguments for that?
Armen Tsirunyan
Basically, testing code should not clutter regular code. IOW, you should be able to write code as if you're not going to test it. Using friend class, or adding the #ifdef macro inside the class itself clutters a class definition with things that aren't directly related to the actual code. `#define private public` then becomes the most ideal solution; however apparently such macro construction is technically illegal, therefore `semiprivate`.
Lie Ryan
@Lie: Thank you. You made your point perfectly clear.
Armen Tsirunyan
+1  A: 

Using the friend method, the declaration would depend on the name of the test class, so if you ever change it's name the declaration has to be changed as well. Moreover I use Unittest++ so the actual test calss name is formed by a macro.

The method with the define is less hassle then. Also, I'd just put the define as a global compiler option instead of the way you show, for example

gcc -DUNIT_TESTING_ON

#ifdef UNIT_TESTING_ON
  public: //or protected maybe
#else
  private:
#endif

Anyone reading this would also see what the purpose is, this is more clear than having to look up the definition of the friend to see why exactly you made it a friend.

stijn
+1  A: 

In the unit test file. You could try

#define private public
#include "Testee.h"

This is what I do, it means that there isn't anything related to unit testing within the header file. I find this very useful as I find it hard to follow when there are lots of #ifdef within my code.

I then have all my other header files before the #define

David Ashmore
Isn't it forbidden to `#define` a reserved keywork ?
ereOn
Some compilers include the access specifier when mangling member function names, which will cause link errors if you break the One Definition Rule like this.
Mike Seymour
It is technically illegal, it may break rule 17.4.3.1.1 P 2 of c++03. But on gcc, and MS compilers it works. I haven't found a compiler where this has caused any problems.
David Ashmore
@David: Presumably you haven't tried Visual Studio 2010.
Mike Seymour
@Mike no I haven't tried it in VS2010
David Ashmore