[Unit-Test] How to test private functions

Is there a way to test the private functions of a class without moving them into public scope during test? What are some strategies for this? I was hoping to add "friend class boost::unit_test::test_suite;" to my class but that didn't work. -- Leif Gruenwoldt

I think there is, or was, a big debate about this in the testing
community. Personally, I believe in testing public interfaces and use
cases. If the private function is so involved it needs its own test,
it may be a sign that it belongs in another class (possibly not
published, eg its header file is not be exported).
HTH,
Noel
On 3/22/06, Leif Gruenwoldt
Is there a way to test the private functions of a class without moving them into public scope during test?
What are some strategies for this?
I was hoping to add "friend class boost::unit_test::test_suite;" to my class but that didn't work.
-- Leif Gruenwoldt _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

Is there a way to test the private functions of a class without moving them into public scope during test?
What are some strategies for this?
I was hoping to add "friend class boost::unit_test::test_suite;" to my class but that didn't work.
Putting aside "why would you need that" question, simple answer is: define test case as a friend to your class. For example if you want to implement test case as free function: class Foo { friend void foo_test(); void private_method(); }; void foo_test() { Foo f; f.private_method(); } If you need multiple test cases having access to the internals you could define test class and make it friend of your class. Next all your test cases will instantiate test class and run test methods. Gennadiy

Gennadiy Rozental wrote:
Is there a way to test the private functions of a class without moving them into public scope during test?
What are some strategies for this?
I was hoping to add "friend class boost::unit_test::test_suite;" to my class but that didn't work.
Putting aside "why would you need that" question, simple answer is: define test case as a friend to your class. For example if you want to implement test case as free function:
class Foo { friend void foo_test();
void private_method(); };
void foo_test() { Foo f;
f.private_method(); }
If you need multiple test cases having access to the internals you could define test class and make it friend of your class. Next all your test cases will instantiate test class and run test methods.
Gennadiy
In my tests, it does not appear possible to use the auto_unit_test.hpp macros in a test class that is attempting to be a friend of a testee class. The compiler complains that the test class is trying to access private data. Does anyone know how to make them work together? (Should this be a separate thread, or is it alright to add it to this one?) Thanks, Ed

Ed Johnson wrote:
Gennadiy Rozental wrote:
Is there a way to test the private functions of a class without moving them into public scope during test?
What are some strategies for this?
I was hoping to add "friend class boost::unit_test::test_suite;" to my class but that didn't work. Putting aside "why would you need that" question, simple answer is: define test case as a friend to your class. For example if you want to implement test case as free function:
class Foo { friend void foo_test();
void private_method(); };
void foo_test() { Foo f;
f.private_method(); }
If you need multiple test cases having access to the internals you could define test class and make it friend of your class. Next all your test cases will instantiate test class and run test methods.
Gennadiy
In my tests, it does not appear possible to use the auto_unit_test.hpp macros in a test class that is attempting to be a friend of a testee class. The compiler complains that the test class is trying to access private data. Does anyone know how to make them work together? (Should this be a separate thread, or is it alright to add it to this one?)
Thanks,
Ed
Whoops, it appears to work just fine with auto_unit_test.hpp macros. My mistake. This is certainly a better way to test the private data than the preprocessor definitions strategy I mentioned in my other post. -Ed --Foo.hpp-- class Foo { friend void foo_test(); private: void private_method(); }; --TestFoo.cpp-- #define BOOST_AUTO_TEST_MAIN #include "Foo.hpp" BOOST_AUTO_TEST_SUITE( my_suite ); BOOST_AUTO_TEST_CASE( foo_test ) { Foo f; f.private_method(); } BOOST_AUTO_TEST_SUITE_END();

On 3/23/06, Leif Gruenwoldt
Is there a way to test the private functions of a class without moving them into public scope during test?
What are some strategies for this?
Try following evil hack.
// someclass_test.hpp
#define private public
#define protected public
#include

Ryo IGARASHI wrote:
On 3/23/06, Leif Gruenwoldt
wrote: Is there a way to test the private functions of a class without moving them into public scope during test?
What are some strategies for this?
Try following evil hack.
// someclass_test.hpp #define private public #define protected public
#include
#undef protected #undef private
Evil, evil, evil! Slightly less so is what I have done in my code. Define a variable (say, TESTING) in the makefile or preprocessor definitions of your test program. In your class definitin, change "private:" to the following: #ifdef TESTING public: #else private: #endif Of course, you leave TESTING undefined (or make sure it is undefined) in your non-test program. It's perhaps not nice to look at, but it's less nasty than the above hack, IMO. Paul

Paul Giaccone wrote:
Ryo IGARASHI wrote:
On 3/23/06, Leif Gruenwoldt
wrote: Is there a way to test the private functions of a class without moving them into public scope during test?
What are some strategies for this?
use protected, then Subclass and override, use friend classes use link seams (See Michael Feather's Working Effectively with legacy code) They all involve some kind of uglyness. In the real world some people ask the question if its private then why are you testing it, on the grounds that anything complicated enough to demand tests, is suggestive of a desire for that functionality to be extracted into its own class/function, which then becomes a public interface on the previously private calls and thus becomes testable. Kevin -- | Kevin Wheatley, Cinesite (Europe) Ltd | Nobody thinks this | | Senior Technology | My employer for certain | | And Network Systems Architect | Not even myself |

Paul Giaccone wrote:
Ryo IGARASHI wrote:
On 3/23/06, Leif Gruenwoldt
wrote: Is there a way to test the private functions of a class without moving them into public scope during test?
What are some strategies for this?
Try following evil hack.
// someclass_test.hpp #define private public #define protected public
#include
#undef protected #undef private
Evil, evil, evil!
Slightly less so is what I have done in my code. Define a variable (say, TESTING) in the makefile or preprocessor definitions of your test program. In your class definitin, change "private:" to the following:
#ifdef TESTING public: #else private: #endif
Of course, you leave TESTING undefined (or make sure it is undefined) in your non-test program.
It's perhaps not nice to look at, but it's less nasty than the above hack, IMO.
Paul
Hi Paul, I wanted to add to your post. I am trying to figure out a good solution to Leif's problem for my own project. Your solution seemed good, but I also want the ability to test just the public interface, without simultaneous access to the private data. When I use the #ifdef TESTING solution, my unit tests never test the classes as they will be used by an end user because all class data is always public. This could lead to a false sense of security from my unit tests. So, here is my addition that I think is more comprehensive. - Separate tests of protected and private members into their own suites. - Surround these suites with: #ifdef TEST_PRIVATE BOOST_AUTO_TEST_SUITE( A_Private ); BOOST_AUTO_TEST_CASE( A_Test1_Private ) { A *p = new A(); BOOST_CHECK( p->privateData == 42 ); } BOOST_AUTO_TEST_CASE( A_Test2_Private ) { A *p = new A(); BOOST_CHECK( p->privateFunction() == "foo" ); } BOOST_AUTO_TEST_SUITE_END(); #endif //TEST_PRIVATE By switching the TEST_PRIVATE definition on or off, I can test either the pure public interface, or the private members temporarily exposed to public. I should probably also surround my public interface tests with: #ifndef TEST_PRIVATE Public Tests... #endif So, that I never accidentally mix the two groups, which would lead to a weakened set of tests on my public interface. You could also extend this to Protected members as well. #ifdef TEST_PROTECTED protected Tests... #endif //TEST_PROTECTED #ifndef TEST_PRIVATE || TEST_PROTECTED Public Tests... #endif //TEST_PRIVATE || TEST_PROTECTED You may want to keep protected tests separate from private tests as well. (and vice versa) #ifdef TEST_PROTECTED #ifndef TEST_PRIVATE protected Tests... #endif //!TEST_PRIVATE #endif //TEST_PROTECTED Any thoughts on this strategy? One potential problem I see is that all private data in every class in the testee app becomes public to each test at the same time. This strategy doesn't let you access private data one class at a time in your tests. Thanks, Ed

Ed Johnson wrote:
Paul Giaccone wrote:
Ryo IGARASHI wrote:
On 3/23/06, Leif Gruenwoldt
wrote: Is there a way to test the private functions of a class without moving them into public scope during test?
What are some strategies for this?
Try following evil hack.
// someclass_test.hpp #define private public #define protected public
#include
#undef protected #undef private
Evil, evil, evil!
Slightly less so is what I have done in my code. Define a variable (say, TESTING) in the makefile or preprocessor definitions of your test program. In your class definitin, change "private:" to the following:
#ifdef TESTING public: #else private: #endif
Of course, you leave TESTING undefined (or make sure it is undefined) in your non-test program.
It's perhaps not nice to look at, but it's less nasty than the above hack, IMO.
Paul
Hi Paul,
I wanted to add to your post. I am trying to figure out a good solution to Leif's problem for my own project. Your solution seemed good, but I also want the ability to test just the public interface, without simultaneous access to the private data. When I use the #ifdef TESTING solution, my unit tests never test the classes as they will be used by an end user because all class data is always public. This could lead to a false sense of security from my unit tests.
I'm not sure why you say the class data is public. The #ifdef I was proposing is for member functions only, so the class data remains private. That said, I've now moved to a less hacky approach, which is to define member functions used by the test programs only that call the private member functions. For example: private: int foo(int a); #ifdef TESTING public: int foo_test(int a) { return foo(a); } #endif I'm not sure if this is a preferable alternative to your idea of separating members into their own test suites, but it certainly seems simpler. Paul

Paul Giaccone wrote:
Ed Johnson wrote:
Paul Giaccone wrote:
Ryo IGARASHI wrote:
On 3/23/06, Leif Gruenwoldt
wrote: Is there a way to test the private functions of a class without moving them into public scope during test?
What are some strategies for this?
Try following evil hack.
// someclass_test.hpp #define private public #define protected public
#include
#undef protected #undef private
Evil, evil, evil!
Slightly less so is what I have done in my code. Define a variable (say, TESTING) in the makefile or preprocessor definitions of your test program. In your class definitin, change "private:" to the following:
#ifdef TESTING public: #else private: #endif
Of course, you leave TESTING undefined (or make sure it is undefined) in your non-test program.
It's perhaps not nice to look at, but it's less nasty than the above hack, IMO.
Paul
Hi Paul,
I wanted to add to your post. I am trying to figure out a good solution to Leif's problem for my own project. Your solution seemed good, but I also want the ability to test just the public interface, without simultaneous access to the private data. When I use the #ifdef TESTING solution, my unit tests never test the classes as they will be used by an end user because all class data is always public. This could lead to a false sense of security from my unit tests.
I'm not sure why you say the class data is public. The #ifdef I was proposing is for member functions only, so the class data remains private.
I typically have my private functions and data all under one label of "private:", so the #idfef TESTING change would affect both for me. I don't believe your post mentioned that is was only meant for functions? Either way, all the classes' private functions would always be presented as public to all the unit tests, which is probably not desirable.
That said, I've now moved to a less hacky approach, which is to define member functions used by the test programs only that call the private member functions. For example:
private: int foo(int a);
#ifdef TESTING public: int foo_test(int a) { return foo(a); } #endif
I'm not sure if this is a preferable alternative to your idea of separating members into their own test suites, but it certainly seems simpler.
Paul
I like that better than my previous approach, too. It allows finer grained control than my strategy. However, I think Gennadiy's solution that he posted in this thread is even less hacky, and gets the job done.

On Wed, May 03, 2006 at 03:03:30PM -0700, Ed Johnson wrote:
private: int foo(int a);
#ifdef TESTING public: int foo_test(int a) { return foo(a); } #endif
I'm not sure if this is a preferable alternative to your idea of separating members into their own test suites, but it certainly seems simpler.
Paul
I like that better than my previous approach, too. It allows finer grained control than my strategy. However, I think Gennadiy's solution that he posted in this thread is even less hacky, and gets the job done.
Obviously, you can't use 'TESTING', it is way too general.
Some macro name will have to be used that will stay constant
forever and will never collide with anyone elses code.
Also, the above is slightly dangerous, as the 'public' would
'leak' beyond the #ifdef when TESTING is defined. You'd have to make
sure that the test block at the end of the class.
Personally, I like the #define private public best, because it doesn't
polute the real code.
You could do the following without running into the danger of writing
test code that accesses something that you want to be private.
Unaltered foo.h:
class Foo {
private:
int x;
int f_priv(int a); // Private function that needs testing.
public:
int f();
};
---
test code:
#define private protected
#include "foo.h"
#undef private
namespace PrivateAccess {
class Foo : public ::Foo {
public:
::Foo::f_priv; // Change access from protected to public.
};
}
namespace Testsuite {
using PrivateAccess::Foo;
// Test code with access to Foo::f_priv, but nothing else:
Foo foo;
void test_func()
{
foo.f_priv(3); // Access private function of Foo
int y = foo.x; // Compile error.
}
}
--
Carlo Wood
participants (8)
-
Carlo Wood
-
Ed Johnson
-
Gennadiy Rozental
-
Kevin Wheatley
-
Leif Gruenwoldt
-
Noel Yap
-
Paul Giaccone
-
Ryo IGARASHI