views:

338

answers:

5

Hello all, I'm facing a nuisance when coding my unit tests using UnitTest++. I'm wondering how to access private member class fields in a clean way (or maybe any way...)

By now, I have a solution to access protected members using a class fixture deriving from the class under test. The following code shows the idea:

struct MyFixture : ClassUnderTest { };

TEST_FIXTURE(MyFixture, OneTest)
{
    do_something();
    CHECK(protected_field == true);
}

Nevertheless, I think this is not very clean, because problems relating inheritance could arise in some configurations and, anyway, just protected members can be accessed and tested.

I tried to declare test classes as friends, but as these are created in some special way by UnitTest++, I haven't managed to do it yet.

Does anyone have any idea of how to make test classes friends of the the classes under test?

Is there another way of approaching this problem in an easier or different way?

Thank you all in advance.

+4  A: 

There's one really ugly but surprisingly useful hack that I commonly use for unit testing:

#define private public
#define protected public

#include "class_to_be_tested.h"

// and here, all class's methods and fields are public :P

DON'T use it for anything else than unit testing!

Also, this method has some limitations -- firstly, not everything private is prefixed with private. Secondly, one popular compiler mangles the access specifier into the linker symbol.

Another, also not so nice method is via casting. You create a structure that has the same fields, but all public, and cast it over the pointer to your private structure. This has the downside however, that the classes need to match exactly:

class my_class
{
private:
   char name[40];
   char grade;
   int age;
public:
   //
}

struct my_class_hack
{
public:
   char name[40];
   char grade;
   int age;

}

struct hack_it* my_class_hacked = (my_class_hack*)ptr;

... you can get nasty surprises however if the compiler plays around with your code, so never use this for production code.

Kornel Kisielewicz
+1, the define thing is an ugly hack but it works!
laura
@laura - not always, but on GCC it worked for us :>
Kornel Kisielewicz
-1 For only hacks. Sorry, why not make code better instead of using hacks if at all possible?
Dmitry
@Dmitry : Once you enter the real world you'll learn that the mythical `client` never allows you to find time for writing "better code", but will demand a 98% code coverage -- that's when you'll learn to love and value hacks like these. I also directly warned that this is an **ugly** hack.
Kornel Kisielewicz
@Kornel Kisielewicz, real world as I know it is full of maintenance after people using hacks. Using less hacks IMHO makes real world a better place. 98% coverage of code full of hacks doesn't, client needs to reconsider his priorities, quick and cheap not always means good. (I'm not referring to you or your code, just generally against hacks of any kind.)
Dmitry
@Dmitry, try telling that to Nokia, and you'd be surprised how much they care...
Kornel Kisielewicz
More to the point, if you're concerned about getting test coverage then why wouldn't you listen to the tests when they tell you something needs to change? That's putting in the work but not getting one of the most important benefits.
GraemeF
+4  A: 

This was the subject of hot debate a few years ago, but the generally accepted result was that you should only test the externally-visible behaviour of your class, and so access to its internal data and behaviour is not required.

While this may not initially sound helpful, you can extract the private parts of your class that you want to test into new classes whose external behaviour is the behaviour you want to test. You can then test these classes in the normal way, and you will improve your overall design.

GraemeF
A: 

One's better off avoiding testing private things. Why do want to test a private_field ? What gets wrongs when the private_field is set to an invalid value ? Is it possible to test for this wrong behavior instead of asserting on the wrong value ?

Other options include

  • play with the preprocessor to make it public when the code is compiled for unit testing

  • extract the private field and the related logic into a new class where it will be public and make the ClassUnderTest relying on this new class.

philippe
+3  A: 

Unit testing is all about testing your objects through their public interface. The fact that it might be hard is why writing testable code is sometimes referred to as art. Not everyone can write testable code right away, that's why people invented XP approach of writing tests first. Sounds unrealistic, works in reality.

However, if you absolutely need to test private functions, here is a list of methods I would consider in order of my own preference:

  1. Private member variables are to be accessed via public setters and getters.

  2. I would recommend making you private member function a non-static non-member function in a namespace that can be called e.g. details or internal. Don't declare it in the header file, just define it in the same file where your class functions are defined. Add its declaration in a myClass_internal.h header file in the unit test project and test it. Difficulties involved depend largely on the complexity of your architecture.

  3. Make your test class inherit from your testable class. This doesn't involve changing your code much, but might require use of multiple inheritance, which in some places is even banned.

  4. Make your test a friend of your testable class. Difficulty depends on the test framework you are using. Say, with gtest that I use, it's pretty hard :)

  5. A hack with redefining public and private should be your absolutely last resort if everything else fails. Although I would rather think of changing the design to a more testable one instead.

Dmitry
A: 

I would also go for th #define Hack,

but also put a #define class struct to get implicit private class data public too.

I must disagree with Dmitry:

1.) this would add interfaces to my production code just for testing and would violate my encapsulation. I do not want clients to have access to my private data

2.) again as seen in 1.) -> good idea, if those interfaces are really only exposed for testing

3.) only works if the access is protected, which somehow also compromisses encapsulation

4.) also means modification of my production code just for testing and even creates a coupling between production code TO my testing code!!!

5.) from your point of view it is right, I rather have ugly testing code than ugly production code :)

TheBigW