49

I am trying to do unit testing (using the Boost unit testing framework) on a C++ class called VariableImpl. Here are the details.

class Variable
{
public:
  void UpdateStatistics (void) {
    // compute mean based on m_val and update m_mean;
    OtherClass::SendData (m_mean);
    m_val.clear ();
  }
  virtual void RecordData (double) = 0;

protected:
  std::vector<double> m_val;

private:
  double m_mean;
};

class VariableImpl : public Variable
{
public:
  virtual void RecordData (double d) {
    // Put data in m_val
  }
};

How can I check that the mean is computed correctly? Note that 1) m_mean is protected and 2) UpdateStatistics calls a method of another class and then clears the vector.

The only way I can see would be to add a getter (for instance, GetMean), but I don't like this solution at all, nor I think it is the most elegant.

How should I do?

And what should I do if I were to test a private method instead of a private variable?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jir
  • 2,985
  • 8
  • 44
  • 66
  • I’ve been meaning to ask something very similar. But in my opinion unit testing and large classes simply doesn’t mix well. – Konrad Rudolph Jul 21 '11 at 15:34
  • Well, can't you see the effects in OtherClass? – R. Martinho Fernandes Jul 21 '11 at 15:35
  • You should read [Enemies of Test Driven Development part I: encapsulation](http://jasonmbaker.wordpress.com/2009/01/08/enemies-of-test-driven-development-part-i-encapsulation/). – André Caron Jul 21 '11 at 15:44
  • 5
    @André In fact, quite a few proponents of TDD say that encapsulation is outdated and shouldn’t be used. Infuriating. This post goes into the direction but stops just short of saying it outright. I’ve given an example in my answer (below) where using a private method *that should be covered by tests* is entirely reasonable. And then the author claims that “testability is a perfectly good reason to make something public” – no, it’s not. If a method shouldn’t be used by the consumer of the class (e.g. since it *cannot* be meaningfully used) it shouldn’t be public. – Konrad Rudolph Jul 21 '11 at 16:01
  • Take a look at some answers to a similar question here:http://stackoverflow.com/questions/249847/how-do-you-test-private-methods-with-nunit – morechilli Jul 21 '11 at 16:28
  • @Konrad: I'm not advocating that encapsulation should not be used, but the post is still worth a read. Often, services covered by private methods can be expressed as their own component and tested individually, then used internally by another class. To quote the article "[...] there are a number of people who have found that this question of testing private methods doesn’t come up much in their practice. They target both testability and good design and find that both goals nurture each other." – André Caron Jul 21 '11 at 17:34
  • @Martinho: suppose `OtherClass` calls a method in another class, which in turn calls a method in another class, and so on. I think it's risky to rely on the effects on other classes (i.e.: you're not testing units anymore, but multiple units at the same time). @André: thanks for the pointer, but after reading it I'm with @Konrad: I don't like the idea of making private methods public. At most, it might be sensible to make them public using conditional compilation (using the hack mentioned in some answers). – Jir Jul 22 '11 at 07:10
  • @Jir If you mocked OtherClass, you could see the effects there. And you'd still be testing only one unit. – R. Martinho Fernandes Jul 22 '11 at 18:51
  • For C++ friend test class declaration inside tested one can work. I answered in details in the original question because this one was marked as a duplicate. – avtomaton Aug 15 '19 at 18:40

8 Answers8

68

Well, unit testing should test units and ideally every class is a self-contained unit – this follows directly from the single responsibility principle.

So testing private members of a class shouldn’t be necessary – the class is a black box that can be covered in a unit test as-is.

On the other hand, this isn’t always true, and sometimes with good reasons (for instance, several methods of the class could rely on a private utility function that should be tested). One very simple, very crufty but ultimately successful solution is to put the following into your unit-test file, before including the header that defines your class:

#define private public

Of course, this destroys encapsulation and is evil. But for testing, it serves the purpose.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • 2
    It seems that this `define` is the least obtrusive solution. I guess the problems I'm facing are more due to the fact that my classes don't follow the single responsibility principle very well. Regarding the toy example I presented, would you suggest that I create a `Mean` class to be used as a private member of `Variable`? That way `Mean` could be tested without any problem. The downside, however, would be proliferation of classes. – Jir Jul 22 '11 at 07:24
  • @Jir In your case, shouldn’t it be enough to unit-test `OtherClass::SendData` since that computes the mean? – Konrad Rudolph Jul 22 '11 at 07:58
  • Actually, yes. I think I'm starting to get the basics of unit testing... thanks! – Jir Jul 22 '11 at 08:10
  • 6
    While this answer works on most compilers it is not standard compliant. You are not allowed to use #define statements that are identical to keywords. See C++98: section 17.4.3.1.1 – Alexander Oh Nov 12 '12 at 11:00
  • @Alex Yes, of course. That’s why I called it crufty and evil. And I wouldn’t recommend it (see the rest of my answer). – Konrad Rudolph Nov 12 '12 at 11:24
  • 1
    Wouldn't friendship more standard compliant than the evil define, and make the testing possible at a negligible encapsulation cost? – paercebal Jun 14 '13 at 15:36
  • 6
    methods that are before any public/private keywords won't became public, btw – RiaD Sep 12 '14 at 06:55
  • @RiaD: Encountered this. `#define class struct` worked. – Alexander Torstling Aug 27 '15 at 15:54
  • This method was very satisfactory to us under Mac OS X. But now we need to build the test suite for Windows environment using Visual Studio: this method is leading to undefined symbols (CL name mangling seems to include the symbol visibility). Any suggestion to make it work with Visual Studio builds ? – Ad N Sep 15 '15 at 10:17
  • defining keywords is **Undefined Behavior**: http://stackoverflow.com/questions/27778908/define-private-to-public-in-c – bolov Aug 23 '16 at 08:49
  • @bolov Well yeah, of course. See comments above. Hence it's "evil" and it should never ship in production code (but already has, for instance in OpenOffice.org). – Konrad Rudolph Aug 23 '16 at 08:51
  • @KonradRudolph I just wanted people to know why it is evil. Some may get the impression that is just an "ugly" but ok hack. – bolov Aug 23 '16 at 11:30
  • I often wonder whether the c++ experts suggesting these "rules" like "private methods don't need testing" have ever written any serious applications. It is not uncommon to have a class with a single method with no parameters and no return values i.e. obj->Run(); – ATL_DEV Jul 09 '18 at 19:03
  • @ATL_DEV Just because it’s common doesn’t mean it’s good. The code you’ve shown should just be a function, not a class (or, if you want to parametrise it, a lambda/closure). More to the point, if you have a private function that benefits from a unit test, make it into a general utility function. There’s no need for these to be private unless they access the internals of a class, and that should only be necessary for thin wrappers. I’ve written enough C++ code (good *and* bad) to have encountered this situation countless times. – Konrad Rudolph Jul 09 '18 at 19:16
  • @KonradRudolph, my comment wasn't referring to you, but to experts who make hard fast rules. I often mark methods as private to tell the client (users of my API) that they are none of their business, whereas the public ones are. Even if the private methods have no side effects in calling them, I see no reason to spill my classes guts since it will only make it more difficult for the client to know which methods to call. – ATL_DEV Jul 10 '18 at 02:40
  • I used to `#define private protected` and then use the tested class as a parent. It's evil too, but a little bit less evil :) And now with newer standard I can just declare my test as a friend of tested class. It added one more benefit - now I can see directly in a class declaration that I already covered some class with a test :) – avtomaton Aug 15 '19 at 19:02
  • @KonradRudolph Could you please elaborate why the example code "obj->Run();" should be a function and not a (active) class? Appreciate your help! – Degoah Jul 14 '23 at 05:44
  • @Degoah Because it could just be a function. Making it a class is strictly more effort and makes the code more complex, for no reason whatsoever. If it’s not obvious why every single-function class can be replaced by a function, watch the presentation [*Stop writing classes*](https://www.youtube.com/watch?v=o9pEzgHorH0) (it’s for Python but the exact same applies to C++ (and other languages). – Konrad Rudolph Jul 14 '23 at 07:05
  • @KonradRudolp Thx for the information and the link! Looking forward to see approaches how to reduce code complexity by moving away from the application of unnecessary paradigms. – Degoah Jul 15 '23 at 09:11
14

For a protected method/variable, inherit a Test class from the class and do your testing.

For a private, introduce a friend class. It isn't the best of solutions, but it can do the work for you.

Or this hack:

#define private public
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
DumbCoder
  • 5,696
  • 3
  • 29
  • 40
  • 6
    Having a `friend` class is too intrusive in my opinion. – Konrad Rudolph Jul 21 '11 at 15:33
  • @Konrad Rudolph - Yes, that is why I said it isn't the best of solutions. And I would assume for testing it should not be that big of a deal. – DumbCoder Jul 21 '11 at 15:43
  • 2
    defining keywords is **Undefined Behavior**: http://stackoverflow.com/questions/27778908/define-private-to-public-in-c – bolov Aug 23 '16 at 08:48
  • @KonradRudolph I don't think that it's too intrusive because only your defined friend class (which is actually your test) will have access. And if you are talking about security aspect, it's a totally different story: private/protected/public does no save your code from injections/reverse engineering etc. at all, it provides protection only from misuse (i. e. improper coding), so it is also not an issue. – avtomaton Aug 15 '19 at 19:06
  • @avtomaton It’s not about security. The point is that the *tested* class needs to declare the test class as `friend`, which means that whenever you add a new unit test class you need to add your non-test code. – Konrad Rudolph Aug 15 '19 at 19:10
9

In general, I agree with what others have said on here - only the public interface should be unit tested.

Nevertheless, I've just had a case where I had to call a protected method first, to prepare for a specific test case. I first tried the #define protected public approach mentioned above; this worked with Linux/GCC, but failed with Windows and Visual Studio.

The reason was that changing protected to public also changed the mangled symbol name and thus gave me linker errors: the library provided a protected __declspec(dllexport) void Foo::bar() method, but with the #define in place, my test program expected a public __declspec(dllimport) void Foo::bar() method which gave me an unresolved symbol error.

For this reason, I switched to a friend based solution, doing the following in my class header:

// This goes in Foo.h
namespace unit_test {   // Name this anything you like
  struct FooTester; // Forward declaration for befriending
}

// Class to be tested
class Foo
{
  ...
private:
  bool somePrivateMethod(int bar);
  // Unit test access
  friend struct ::unit_test::FooTester;
};

And in my actual test case, I did this:

#include <Foo.h>
#include <boost/test/unit_test.hpp>

namespace unit_test {
  // Static wrappers for private/protected methods
  struct FooTester
  {
    static bool somePrivateMethod(Foo& foo, int bar)
    {
      return foo.somePrivateMethod(bar);
    }
  };
}

BOOST_AUTO_TEST_SUITE(FooTest);
BOOST_AUTO_TEST_CASE(TestSomePrivateMethod)
{
  // Just a silly example
  Foo foo;
  BOOST_CHECK_EQUAL(unit_test::FooTester::somePrivateMethod(foo, 42), true);
}
BOOST_AUTO_TEST_SUITE_END();

This works with Linux/GCC as well as Windows and Visual Studio.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
mindriot
  • 5,413
  • 1
  • 25
  • 34
4

A good approach to test the protected data in C++ is the assignment of a friend proxy class:

#define FRIEND_TEST(test_case_name, test_name)\
friend class test_case_name##_##test_name##_Test

class MyClass
{
    private:
        int MyMethod();
        FRIEND_TEST(MyClassTest, MyMethod);
};

class MyClassTest : public testing::Test
{
    public:
      // ...
        void Test1()
        {
            MyClass obj1;
            ASSERT_TRUE(obj1.MyMethod() == 0);
        }

        void Test2()
        {
            ASSERT_TRUE(obj2.MyMethod() == 0);
        }

        MyClass obj2;
};

TEST_F(MyClassTest, PrivateTests)
{
    Test1();
    Test2();
}

See more Google Test (gtest).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
sergeyxzc
  • 515
  • 6
  • 4
1

While in my opinion the need of testing private members/methods of a class is a code smell, I think that is technically feasible in C++.

As an example, suppose you have a Dog class with private members/methods except for the public constructor:

#include <iostream>
#include <string>

using namespace std;

class Dog {
  public:
    Dog(string name) { this->name = name; };

  private:
    string name;
    string bark() { return name + ": Woof!"; };
    static string Species;
    static int Legs() { return 4; };
};

string Dog::Species = "Canis familiaris";

Now for some reason you would like to test the private ones. You could use privablic to achieve that.

Include a header named privablic.h along with the desired implementation like that:

#include "privablic.h"
#include "dog.hpp"

then map some stubs according to types of any instance member

struct Dog_name { typedef string (Dog::*type); };
template class private_member<Dog_name, &Dog::name>;

...and instance method;

struct Dog_bark { typedef string (Dog::*type)(); };
template class private_method<Dog_bark, &Dog::bark>;

do the same with all static instance members

struct Dog_Species { typedef string *type; };
template class private_member<Dog_Species, &Dog::Species>;

...and static instance methods.

struct Dog_Legs { typedef int (*type)(); };
template class private_method<Dog_Legs, &Dog::Legs>;

Now you can test them all:

#include <assert.h>

int main()
{
    string name = "Fido";
    Dog fido = Dog(name);

    string fido_name = fido.*member<Dog_name>::value;
    assert (fido_name == name);

    string fido_bark = (&fido->*func<Dog_bark>::ptr)();
    string bark = "Fido: Woof!";
    assert( fido_bark == bark);

    string fido_species = *member<Dog_Species>::value;
    string species = "Canis familiaris";
    assert(fido_species == species);

    int fido_legs = (*func<Dog_Legs>::ptr)();
    int legs = 4;
    assert(fido_legs == legs);

    printf("all assertions passed\n");
};

Output:

$ ./main
all assertions passed

You can look at the sources of test_dog.cpp and dog.hpp.

DISCLAIMER: Thanks to insights of other clever people, I have assembled the aforementioned "library" able to access to private members and methods of a given C++ class without altering its definition or behaviour. In order to make it work it's (obviously) required to know and include the implementation of the class.

NOTE: I revised the content of this answer in order to follow directives suggested by reviewers.

altamic
  • 35
  • 2
  • 2
    Please don't just post some tool or library as an answer. At least demonstrate [how it solves the problem](http://meta.stackoverflow.com/a/251605) in the answer itself. – Baum mit Augen Jun 25 '17 at 20:59
1

Unit test VariableImpl such that if its behavior is ensured, so is Variable.

Testing internals isn't the worst thing in the world, but the goal is that they can be anything as long as the interfaces contracts are ensured. If that means creating a bunch of weird mock implementations to test Variable, then that is reasonable.

If that seems like a lot, consider that implementation inheritance doesn't create great separation of concerns. If it is hard to unit test, then that is a pretty obvious code smell for me.

Tom Kerr
  • 10,444
  • 2
  • 30
  • 46
0

Example from the Google testing framework:

// foo.h
#include "gtest/gtest_prod.h"
class Foo {
  ...
 private:
  FRIEND_TEST(FooTest, BarReturnsZeroOnNull);
  int Bar(void* x);
};

// foo_test.cc
...
TEST(FooTest, BarReturnsZeroOnNull) {
  Foo foo;
  EXPECT_EQ(0, foo.Bar(NULL));
  // Uses Foo's private member Bar().
}

The main idea is the use of the friend C++ keyword. You can extend this example as follows:

// foo.h
#ifdef TEST_FOO
#include "gtest/gtest_prod.h"
#endif

class Foo {
  ...
 private:
  #ifdef TEST_FOO
  FRIEND_TEST(FooTest, BarReturnsZeroOnNull);
  #endif
  int Bar(void* x);
};

You can define the TEST_FOO preprocessor symbol in two ways:

  1. within the CMakeLists.txt file

     option(TEST "Run test ?" ON)
     if (TEST)
       add_definitions(-DTEST_FOO)
     endif()
    
  2. as arguments to your compiler

     g++ -D TEST $your_args
    
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
user1823890
  • 704
  • 8
  • 7
0

I generally suggest testing the public interface of your classes, not the private/protected implementations. In this case, if it can't be observed from the outside world by a public method, then the unit test may not need to test it.

If the functionality requires a child class, either unit test the real derived class OR create your own test derived class that has an appropriate implementation.

Mark B
  • 95,107
  • 10
  • 109
  • 188