By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,982 Members | 1,932 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,982 IT Pros & Developers. It's quick & easy.

Testing protected or private functionality?

P: n/a
I'm using a simple unit test architecture I found in "Thinking in C++".
I just decided I wanted to place some member functions out from public
into a protected scope. Problem is that my tests want to access those
functions...bummer. What have other people done when faced with this
problem or just the general problem of testing functionality
encapsulated in a private manner?

Apr 17 '06 #1
Share this Question
Share on Google+
12 Replies


P: n/a
Noah Roberts wrote:
I'm using a simple unit test architecture I found in "Thinking in
C++". I just decided I wanted to place some member functions out from
public into a protected scope. Problem is that my tests want to
access those functions...bummer. What have other people done when
faced with this problem or just the general problem of testing
functionality encapsulated in a private manner?


Duplicate the testing functionality in the class and #ifdef it so that
the final product doesn't have it:

class A {
void someprivatefunction(int);
public:
#ifdef DO_TEST
void test() {
someprivatefunction(42);
assert(somepostcondition);
}
#endif
};

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Apr 17 '06 #2

P: n/a
Noah Roberts wrote:
I'm using a simple unit test architecture I found in "Thinking in C++".
I just decided I wanted to place some member functions out from public
into a protected scope. Problem is that my tests want to access those
functions...bummer. What have other people done when faced with this
problem or just the general problem of testing functionality
encapsulated in a private manner?

You could either make the test class a friend, or refactor the private
methods into another object and test that.

--
Ian Collins.
Apr 17 '06 #3

P: n/a

Ian Collins wrote:
Noah Roberts wrote:
I'm using a simple unit test architecture I found in "Thinking in C++".
I just decided I wanted to place some member functions out from public
into a protected scope. Problem is that my tests want to access those
functions...bummer. What have other people done when faced with this
problem or just the general problem of testing functionality
encapsulated in a private manner?

You could either make the test class a friend, or refactor the private
methods into another object and test that.


That would work ok for privates, an exposed pimpl of sorts, but for
protected members it could be a bit problematic.

Apr 17 '06 #4

P: n/a
Noah Roberts wrote:
Ian Collins wrote:
Noah Roberts wrote:
I'm using a simple unit test architecture I found in "Thinking in C++".
I just decided I wanted to place some member functions out from public
into a protected scope. Problem is that my tests want to access those
functions...bummer. What have other people done when faced with this
problem or just the general problem of testing functionality
encapsulated in a private manner?


You could either make the test class a friend, or refactor the private
methods into another object and test that.

That would work ok for privates, an exposed pimpl of sorts, but for
protected members it could be a bit problematic.

Which option and how would it be problematic?

--
Ian Collins.
Apr 17 '06 #5

P: n/a
Noah Roberts wrote:
I'm using a simple unit test architecture I found in "Thinking in C++".
I just decided I wanted to place some member functions out from public
into a protected scope. Problem is that my tests want to access those
functions...bummer. What have other people done when faced with this
problem or just the general problem of testing functionality
encapsulated in a private manner?


There's a spectrum of answers, depending on whether tests are written before
or after the tested code.

Under pure Test Driven Development, you write failing test cases, then write
the code to pass them. Then you refactor the code to make methods generally
shorter and less redundant.

At refactor time, methods should Extract Method their common code into
private methods that only they call. Tests will still cover these private
methods' behaviors. The original test cases that created these behaviors
will still defend the behaviors against change.

As a module grows under test, programmers might need to add behavior
directly to these private methods. At this time, they can write public
wrappers for the methods, or make the methods public. If a test case can
easily use a method, clients ought to be allowed to use it the same way,
too.

If the method is not yet ready for re-use by production code, the programmer
can supply a sternly-worded comment. Static type checking becomes less
important as programmers invest in test cases for run-time checking.

When programmers add new tests to legacy code, they should start low, to
test soft targets and begin to make the code ready for refactoring and more
tests. Low targets are typically private. I publish them like this:

#ifdef _DEBUG
# define DEBUG_(X_) X_
#else
# define DEBUG_(X_)
#endif

....

private:
DEBUG_(public:)
void secretlyTestMe();

Now a test case can grab secretlyTestMe(), but when we compile in release
mode we still get the static type checking on this class's private things.
(_DEBUG is often defined when the Standard NDEBUG is not, and the DEBUG_()
macro now becomes useful for other optional code, too.)

Some systems can make the test case a friend. I prefer test runners like
CppUnitLine that use a Test Collector to dynamically generate a class for
each test case. This thing's name is difficult to type, and classes should
have more than one test case. Listing them in each tested class is not just
a pain, it's also an invitation for cascading recompiles.

--
Phlip
http://www.greencheese.org/ZeekLand <-- NOT a blog!!!
Apr 17 '06 #6

P: n/a

Noah Roberts wrote:
I'm using a simple unit test architecture I found in "Thinking in C++".
I just decided I wanted to place some member functions out from public
into a protected scope. Problem is that my tests want to access those
functions...bummer. What have other people done when faced with this
problem or just the general problem of testing functionality
encapsulated in a private manner?


Thanks for the ideas. After looking at the matter and the responses I
think I favor something like this:

class Test { public: virtual void test() = 0; };
class TOut
{
class TestTout;
protected:
void print(std::string x) { cout << x; }
public:
static std::auto_ptr<Test> test();
};

class TOut::TestTout : public Test
{
TOut tout;
public:
void test() { tout.print("TEST"); }
};

std::auto_ptr<Test> TOut::test() { return std::auto_ptr<Test>(new
TOut::TestTout()); }

int main()
{
std::auto_ptr<Test> t = TOut::test();
t->test();

int x;
cin >> x;
}

This still allows me to keep the test and the subject pretty separated
(can declare the two in separate headers) and gives me the access I
need. I have to declare the test harness in the class I am testing and
provide a factory for it but that is pretty minor cost.

Apr 17 '06 #7

P: n/a
Noah Roberts wrote:
Noah Roberts wrote:
I'm using a simple unit test architecture I found in "Thinking in C++".
I just decided I wanted to place some member functions out from public
into a protected scope. Problem is that my tests want to access those
functions...bummer. What have other people done when faced with this
problem or just the general problem of testing functionality
encapsulated in a private manner?

Thanks for the ideas. After looking at the matter and the responses I
think I favor something like this:

class Test { public: virtual void test() = 0; };
class TOut
{
class TestTout;
protected:
void print(std::string x) { cout << x; }
public:
static std::auto_ptr<Test> test();
};

class TOut::TestTout : public Test
{
TOut tout;
public:
void test() { tout.print("TEST"); }
};

std::auto_ptr<Test> TOut::test() { return std::auto_ptr<Test>(new
TOut::TestTout()); }

int main()
{
std::auto_ptr<Test> t = TOut::test();
t->test();

int x;
cin >> x;
}

This still allows me to keep the test and the subject pretty separated
(can declare the two in separate headers) and gives me the access I
need. I have to declare the test harness in the class I am testing and
provide a factory for it but that is pretty minor cost.

Have you looked at unit test frameworks like CppUnitLite or CppUnit?

--
Ian Collins.
Apr 17 '06 #8

P: n/a
Noah Roberts wrote:
class Test { public: virtual void test() = 0; };


This solution is way too complicated for the simple problem.

"private" is not some hallowed sacred concept. It is a tool, to be picked up
and put down at need.

--
Phlip
http://www.greencheese.org/ZeekLand <-- NOT a blog!!!
Apr 18 '06 #9

P: n/a
Ian Collins wrote:
Have you looked at unit test frameworks like CppUnitLite or CppUnit?


He's not implementing the framework. (Hard to tell, but true.) He's using
main() as the test case, and showing how he can make a chain of permitted
access between main() and the private function.

--
Phlip
http://www.greencheese.org/ZeekLand <-- NOT a blog!!!
Apr 18 '06 #10

P: n/a

Phlip wrote:
Noah Roberts wrote:
class Test { public: virtual void test() = 0; };


This solution is way too complicated for the simple problem.

"private" is not some hallowed sacred concept. It is a tool, to be picked up
and put down at need.


Actually, it is very simple and not prone to one error I want to
totally avoid:

class X
{
protected:
#ifdef DEBUG
public:
#endif
int f() const;
};

#ifdef DEBUG
class XTest : public Test
{
X x;
public:
void run() { test(x.f() == 5); }
};
#endif

.... somewhere else in someone else's code....

X x;
x.f();

Now the system compiles and runs in debug mode only...a stupid error
for sure, but one that could cost a lot of time right before product
release that would require going through the testing phaze again. If
you hire inexperienced programmers, like interns, they might very well
miss something like that...hell, I could do it on a Monday. That just
seems to introduce too much confusion to me.

On the other hand, having the class return an inner test object that no
client knows the interface for (unless they include test headers)
offers a bit more abstraction and protection. Plus, there is no
reason, other than testing, for someone to make calls to the test
interface...but someone might think they want access to a member that
is public in debug build as it actually acomplishes something.

I also have a bit of a thing against the preprocessor. I like to avoid
using it when I can and use the language and classes instead.

Apr 18 '06 #11

P: n/a

Ian Collins wrote:
Have you looked at unit test frameworks like CppUnitLite or CppUnit?


I've started using boost test at home, but I don't have the option at
work. I kind of shuffled in the testing framework from Thinking in
C++. Very simplistic but it meets my immediate needs and it will be
easy to replace if I am told to.

Apr 18 '06 #12

P: n/a
Noah Roberts wrote:
... somewhere else in someone else's code....

X x;
x.f();

Now the system compiles and runs in debug mode only...a stupid error
for sure, but one that could cost a lot of time right before product
release that would require going through the testing phaze again.
This is a different consideration. But first: I use the DEBUG trick ONLY
because I'm working a legacy project, with tests written long after the
tested code.

Regardless whether I do or not, our build script builds and tests each of
the Debug version, the Profiling version and the Release version each time
anyone submits code. If they break any of those builds they get an e-mail.

(They get the e-mail anyway; that's a small risk they might stop reading
it!;)
If
you hire inexperienced programmers, like interns, they might very well
miss something like that...hell, I could do it on a Monday. That just
seems to introduce too much confusion to me.
That's what pair programming and other code reviews are for.
I also have a bit of a thing against the preprocessor. I like to avoid
using it when I can and use the language and classes instead.


Use the preprocessor for...

- token pasting
- conditional compilation
- stringerization

Then don't abuse those abilities. ;-)

If you write tests at the same time as the tested code, your interface
should be a little wider, and a little healthier. This is not the same thing
as adding extra Get methods for your private variables. And no
private-but-public tricks, either.

--
Phlip
http://www.greencheese.org/ZeekLand <-- NOT a blog!!!
Apr 18 '06 #13

This discussion thread is closed

Replies have been disabled for this discussion.