The Design of Software (CLOSED)

A public forum for discussing the design of software, from the user interface to the code architecture. Now closed.

The "Design of Software" discussion group has been merged with the main Joel on Software discussion group.

The archives will remain online indefinitely.

C++ unit testing

I've started using CppUnit to unit-test C++ code. In the unit test case code, I sometimes want to use (invoke)  private implementation details of the class being tested. How do you do this: do you insert "friend" statements in the code being tested, or what?
Christopher Wells Send private email
Sunday, May 14, 2006
 
 
I make all unit tests class friends of the classes they are testing. This I way I can test evrything that needs to be tested without making too much public.

Making state public just so you can test is a risk practice IMHO. Friend is the perfect balance.
son of parnas
Sunday, May 14, 2006
 
 
On that same track,

Is it acceptable to add a dependancy on the test existance for the code?

Or rather, if you have to do special things in your code to get it to work with tests (adding friend statements, or adding parameters to accept a junk socket, etc) is that considered viable or a no-no?

Half of the stuff I want to test seems to require me to rewrite the code I'm testing to accept dummy underlying objects and it seems like a big hassle.
Josh McFarlane Send private email
Sunday, May 14, 2006
 
 
I don't do anything special to test code other than make test classes friends.

I don't do anything special because I consider that good design and implementation means that code is testable. The code should never know it is under test.

The primary ways of doing this are:
1. Parameterization. You should be able to construct objects using different implementations of underlying services.
2. To support (1) use abstract base classes so you can create mock objects for testing and other objects for different production environments.

Well, I lied a little. I do add more tracking in my code to make testing easier. I might track the number of messages sent so I can do a quick check against the expected number sent and actual sent. But this operates the same under test or under deployment and you often need these kind of stats anyone for monitoring.
son of parnas
Sunday, May 14, 2006
 
 
> ... adding parameters to accept a junk socket ...

Another thing I do, to vary the behaviour of the class being tested to make it work in the unit-test environment, is I redeclare as virtual some (typically private) implementation methods of the class being tested. I then derive from that class and unit-test the derived class, for example:

* The Foo class which you want to test has a private sendToSocket method
* So you reclare the Foo::sendToSocket method as virtual
* You derive from the class (i.e. define a TestableFoo class) with an overriden implementation of the sendToSocket method
* Your TestFoo test suite then instantiates and tests the TestableFoo class instead of testing the underlying Foo class.

One other thing I'm having trouble now with is testing some code whose behaviour depends on the current date and time, which it discovers by calling a static method of a DateAndTime class: because the DateAndTime class has static methods, the code being tested doesn't take an instance of this class as a constructor parameter, so I can't pass in a different version of this class. Two solutions I can think of are:

a) Test cases fiddle with (poke) the clock of the system being tested

b) Or, use #ifdef IS_TESTCASEPROJECT in the DateAndTime class, to change the implementation of the DateAndTime class to which the test code is being linked.
Christopher Wells Send private email
Sunday, May 14, 2006
 
 
> which it discovers by calling a static method of
> a DateAndTime

Statics are generally a bad move for testing. Make a date time service. Make one for unit testing that has known answers so you can check for expected results.

Then either:
1. pass that service into your objects
2. make a factory/singleton that you load differently in your test main than production main.
son of parnas
Sunday, May 14, 2006
 
 
c) DateAndTimeService (interface)
DateAndTimeServiceImpl (class encapsulating DateAndTime)
DateAndTimeServiceMock (mock object)

Now, either pass the DateAndTimeService with the constructor or use a framework that allows you to switch implementations.
Dave
Sunday, May 14, 2006
 
 
In your unit test, simply redefine "private" and "protected" to be "public" before including the header files of the classes you're testing.

You can now write code which calls the protected/private methods and access their members directly.

The private/protected is ONLY enforced by the compiler at the time of use; and the #define rewrites that for you.

You can even link against the object files you've built previously, because changes in visibility make no difference to the object's linkage, layout or size.


Do not use this in production code on pain of pain. For unit tests, it's right handy tho.
Katie Lucas
Wednesday, May 17, 2006
 
 
"In your unit test, simply redefine "private" and "protected" to be "public" before including the header files of the classes you're testing."

That's a sweet idea!
KenE Send private email
Wednesday, May 17, 2006
 
 
> That's a sweet idea!

It's pretty sour. You are changing your code to make a test, anyone else can flip the same switch, and someone has to rememember to set the right flags everywhere.

Use friends and it just works.
son of parnas
Wednesday, May 17, 2006
 
 
You don't have to flip switches, you just go;

#define protected public

#include "class_i_want_to_test.h"

int main()

{

  class_i_want_to_test foo;

  cout << foo.sekretmethod() << endl;

}


The code for the class can live in the same .o file it always has done.
Katie Lucas
Thursday, May 18, 2006
 
 
> #define protected public

Double ugh on many grounds, but it is also completely unecessary. Why would you want to do it this way?
son of parnas
Thursday, May 18, 2006
 
 
An advantage of "#define private public" in a test module (before including the header file for the class being tested) is that the source for the class being tested does not have to be touched (unlike using friend...).  It's like music by Stravinsky: ugly only if you are rigid about what constitutes beauty.
Will Dowling Send private email
Thursday, May 18, 2006
 
 
> It's like music by Stravinsky: ugly only if you are
> rigid about what constitutes beauty.

Stravinsky changed music. Hacking scoping is hardly in the same class.

If your idea of beauty is ifdefs all over the place, subverting protection, and ignoring inbuilt methods for accomplishing something, then be beautiful.
son of parnas
Thursday, May 18, 2006
 
 
I don't think Stravinsky wrote anything that comes close to be considered ugly. Maybe Schönberg, Berg, and the 12-tone crew, but not Igor. ;-)
MBJ Send private email
Thursday, May 18, 2006
 
 
> If your idea of beauty is ifdefs all over the place,

It isn't.  In general, the fewer, and more highly localized, the ifdefs, the better.  At least that's my aesthetic.  Like listening to 20th c. music, discernment is required.

> subverting protection,

Well, in general I'm not a fan of subverting protection, either. For this use (testing private methods), however, subverting protection in a caller, seems better than making a class know ahead of time how it's to be tested.

> and ignoring inbuilt methods

Not quite sure what you're getting at here.  The use of ifdefs is every bit as much as inbuilt as friend. Unless you're talking about the *implementation* of C++ (but you wouldn't want to look inside that black box, would you?)
Will Dowling Send private email
Thursday, May 18, 2006
 
 
#define protected public
is illegal C++ code because it is illegal to #define a reserved word. I will never use the above code even if some compiler allows it.

http://www.gotw.ca/gotw/076.htm
nullptr
Thursday, May 18, 2006
 
 

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics
 
Powered by FogBugz