128

I am in the process of writing some unit tests. In particular I want to test some private methods.

So far the I have come up with using.

#define private public

But I am not happy with this as it will destroy all encapsulation from the point of view of the unit test.

What methods do you use to unit-test private methods.

Michas
  • 8,534
  • 6
  • 38
  • 62
Mumbles
  • 1,654
  • 3
  • 14
  • 16
  • 2
    what kind of C++ unit testing framework are you using? – Laurens Ruijtenberg Sep 09 '10 at 12:52
  • 4
    Note that there are ways to use private members in C++. You can read about it in my blog: http://bloglitb.blogspot.com/2010/07/access-to-private-members-thats-easy.html – Johannes Schaub - litb Sep 09 '10 at 21:36
  • 2
    `#define private public` - it is illegal to define a reserved word. – JBentley Mar 16 '13 at 01:37
  • You can use commercial products such as [Isolator++](https://www.typemock.com/docs?book=Ipp&page=faking_private_and_protected_m.htm) to fake private and protected methods. – Sam Nov 02 '17 at 11:59
  • 7
    This is not a duplicate. This question is about C++ (which has `friend`) while the other question is nonspecific. Its top answer is for Java, suggesting reflection. – Qwertie Nov 23 '18 at 02:07
  • 2
    (1) I never adjust the code to the needs of the test. (2) It is very useful to test private methods, especially in early stages of code writting, when that methods are math complicated (a math formula about 1800 chars). Testing the high level public methods is a later test. So `#define private public` before `#include` and `#undef private` after, works fine for me, but also I don't like it. – Chameleon May 04 '22 at 08:26
  • @Baum mit Augen how do you have gold C++ badge but also cannot tell the difference between C++ and Java? – Tomáš Zato May 14 '23 at 18:12
  • I would argue that `private:` members should be tested in terms of tests that exercise the `public:` parts that *use* those private parts - not specific tests for the privates directly. – Jesper Juhl May 17 '23 at 10:45

8 Answers8

89

Rather than the nasty #define hack you mention in the question, a cleaner mechanism is to make the test a friend of the class under test. This allows the test code (and just the test code) access to the privates, whilst protecting them from everything else.

However, it is preferable to test through the public interface. If your class X has a lot of code in the private member functions then it might be worth extracting a new class Y which is used by the implementation of class X. This new class Y can then be tested through its public interface, without exposing its use to the clients of class X.

Anthony Williams
  • 66,628
  • 14
  • 133
  • 155
  • 4
    What one should do is use a compiler define for unit testing and #ifdef UNIT_TESTING friend void UnitTestFcn() #endif – iheanyi Apr 21 '14 at 15:25
  • Yes, you can make the test conditionally a friend. It is still preferable to test through the public interface. – Anthony Williams Apr 22 '14 at 08:30
  • So you make the methods public one way or another :( – CpILL Jul 13 '17 at 06:59
  • 1
    Yes, test public methods, but change which class they are public on. If the new class `Y` is named `lib_namespace::detail::X_private_impl` then it's unlikely to be used casual users of `X`. – Anthony Williams Jul 31 '17 at 09:43
  • "If your class X has a lot of code in the private member functions then it might be worth extracting a new class Y which is used by the implementation of class X." At the cost of bloating the namespace and increasing the cost of understanding the code. – quant_dev Aug 19 '17 at 18:01
81

If you're using Google Test, you can use FRIEND_TEST to easily declare your test fixture as a friend to the class under test.

And you know, if testing private functions were unequivocally bad like some of the other answers were saying, then it probably wouldn't be built into Google Test.

You can read more about when testing private functions is good or bad in this answer.

lidaobing
  • 1,005
  • 13
  • 26
jlstrecker
  • 4,953
  • 3
  • 46
  • 60
  • 4
    This clearly an instance of [appeal to authority](https://yourlogicalfallacyis.com/appeal-to-authority) but ... what an authority Google Test is ! Best answer. – Olórin Aug 31 '16 at 21:01
  • 3
    The google test docs that you link to strongly suggest to redesign over testing private methods. – cevaris Dec 18 '16 at 14:56
  • Yes, consider redesigning (see the answer I linked to in my post), but "If you absolutely have to test non-public interface code though, you can." – jlstrecker Dec 20 '16 at 03:35
72

If the methods are complex enough to warrant testing in isolation, then refactor them into their own class(es) and test via their public interface(s). Then use them privately in the original class.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • 3
    yes, the urge to unit test private methods is usually a design smell. – Felix Ungman Sep 09 '10 at 12:57
  • 86
    huh? why on earth should public functions warrant more testing than private ones? – Assaf Lavie Sep 09 '10 at 13:02
  • 41
    I don't understand why wanting to unit test a private method is design smell. Lets say, I start writing a class, and at the same time write the unit-test, before I start writing the public function, I write some fairly simple private functions that I want to prove works before I start to implement the public functions. – Mumbles Sep 09 '10 at 13:19
  • 10
    @Assaf: private functions can't be tested unintrusively, so if they need testing in isolation you must either be make them public (where they are, or in another class), or add an intrusive testing mechanism. My suggestion is to refactor so that all code can be tested unintrusively; in my view (which not everyone will share) this also gives a cleaner design, by reducing the responsibilities of the original class, and allowing reuse of what was previously private functionality. Use Anthony's suggestion of a friend test class if you prefer large classes with multiple responsibilities. – Mike Seymour Sep 09 '10 at 13:23
  • 8
    @David: it's a smell because it indicates that the class has multiple responsibilities (implementing its public interface, and also implementing private functionality). It may be a cleaner design to delegate the private functionality to other classes, rather than to private methods. – Mike Seymour Sep 09 '10 at 13:25
  • @Assaf: public functions warrant more testing because they are part of the interface of the class. Private functions aren't. You can test private functions (or other internal components which are not accessible to outsiders, e.g. line 4 of some public function) indirectly via the functions which call them, or you use friends, or you define what they do properly and test that via a public interface. I prefer 1 and 3 over 2, so if something needs direct testing I want it to be public (somewhere). As a direct consequence of that policy, things that aren't public don't need direct testing. – Steve Jessop Sep 09 '10 at 13:40
  • 1
    If you do extract a class to allow for testing, be sure to think carefully about which methods should be included and how the class should be named. Done correctly, you've now not only made the class easier to test, but have also made it easier to understand for the maintenance engineer who will eventually inherit your code. – Dan Bryant Sep 09 '10 at 13:43
  • 8
    @Assaf: looking at it another way, I think that tests should not need to be removed if you change the implementation details of the class without changing its public interface (or protected, if you like). You might want to *add* tests after a re-write, when you're white-box testing, to catch new "risky" cases. You shouldn't have to remove them -- the new implementation is supposed to do every significant thing the old one did. But private functions are implementation details. Tests which stop working when an implementation detail changes, even though nothing is actually broken, are nuisances. – Steve Jessop Sep 09 '10 at 13:47
  • 3
    @David: in your particular case, I'd call that ad-hoc programmer testing. Write the test as part of the class (perhaps a public `test_internals()` function which returns true or false. Perhaps a test class which is a `friend` of your class), or make the functions temporarily public. Test your private functions. Then write your public functions, make sure they pass all their tests. Once they do, you no longer need or want your tests to ensure that your class contains that particular implementation detail, so don't check those tests in. – Steve Jessop Sep 09 '10 at 13:54
  • 2
    you should ideally unit-test all functions... (ala Haskell's QuickCheck) if you never unit-test private methods, how can you trust them being correct within your own classes? – gnzlbg Mar 21 '14 at 16:53
  • I agree with @gnzlbg. All functions should be unit tested. You should be unit testing as you develop the functions. Testing the public interface of a class should also be done. But the further away you move in abstraction, the less you can fine test. If you only test at the public level, your tests have less meaning. Imagine a class w/ private method sum(a,b). Originally implemented correctly, your public xface tests pass. Someone later breaks sum() in such a way that the xface tests still pass. So, you happily continue shipping a buggy product. Unit test all functions - Murphy finds us all! – iheanyi Apr 21 '14 at 15:30
  • So, rather than write a million unit test of the public interface so that you exercise everything behind it in all ways possible, why don't you just write a smaller number of tests for each function and a smaller number for the public interface? Can you imagine the hoops you'd need to jump through to get the public interface to test all possible permutations of inputs and method calls to get the parameters of a particular private method to take a certain value? Much easier to just test the method itself (and much easier to get right). – iheanyi Apr 21 '14 at 15:39
  • 1
    @iheanyi: "Much easier to just test the method itself" - indeed, that's exactly what I was suggesting. Take the (currently untestable) private method; move it out of the original class, making it public (and hence testable); refactor the original class to (privately) use the (now public, and testable) function. I certainly wasn't suggesting trying to test the private method indirectly via the original public interface - as you say, that would be madness. – Mike Seymour Apr 21 '14 at 15:47
  • 1
    Hmm, how would you deal with the problem where this private method needs access to private class fields (after being refactored and moved out of the original class)? Seems simpler to add conditional defines to friend a unit test class/function than having to friend lots of public functions. – iheanyi Apr 21 '14 at 16:50
  • 1
    @iheanyi: Refactor the private method, and whatever internal stuff it depends on, into a separate class, as the answer says. Hopefully that will simplify the original class by decoupling it from that stuff - although if it still needs access, then the new class will need to expose it. No need to friend anything, or to have anything conditional. But this isn't really the place for an extended discussion of refactoring techniques. – Mike Seymour Apr 21 '14 at 17:06
  • Hmm, yeah, this would work. About the only place where you'd need to friend a class would be classes that implement a passkey or attorney-client (or something related to provide fine grained access control). – iheanyi Apr 21 '14 at 17:21
  • 1
    You really don't need a separate class to accomplish this for many (most?) applications. Just move the actual implementation into a TU-local function (static or unnamed namespace) and add ref parameters for member variables, then call the method from your class and the test case. No friends, redefines, or new classes, provides referential transparency for maintainers, and more or less still follows the interface of the type under testing. – flatline Jan 09 '17 at 17:53
  • A solution, for some situations, is to define a class with public member functions and test that class. Then you can define the class with functions as a private data member in the class that would otherwise have private member functions. Inside that class, you'll have to call on your class with member functions as a data member. Like `base_class.class_with_functions.function()`. This might not work if the class to be included as a data member has static variables, in some cases. – JasTonAChair Apr 07 '17 at 05:45
  • You shouldn't split up a class, just so you can test private methods. But a private method may expect it's object to be in a given state, which only the public interface would guarantee. I use testing of private methods a lot during initial creation of a class (test driven development, anyone?) by making it all temporarily public. Eventually I'll move all my testing to the public interface. In any case, this is only an issue in OO languages, so don't get too religious about it. – Erik Bongers Apr 15 '22 at 20:51
35

Make the test class as the friend of the original class. This friend declaration will be inside the #define UNIT_TEST flag.

class To_test_class {
   #ifdef UNIT_TEST
     friend test_class;
   #endif
}

Now for your unit test you will compile the code with flag -DUNIT_TEST. This way you will be able to test the private function.

Now your unit test code will not be pushed into production environment, as UNIT_TEST flag will be false. Hence the code is still secure.

Also you will not need any special library for unit testing.

Elias Kosunen
  • 433
  • 7
  • 20
Manoj R
  • 3,197
  • 1
  • 21
  • 36
  • One could also put the friend in a `#ifdef DEBUG`, then you don't need to extra flags. – Ant6n Mar 03 '16 at 21:36
  • The `#ifdef` and `#define` parts are unnecessary. – Qwertie Nov 23 '18 at 02:04
  • 1
    More specifically (1) if `test_class` has been forward-declared, even without a body, you don't need `#ifdef`, and (2) if you write `friend class ::test_class`, you don't need `#ifdef` (assuming `test_class` is in the global namespace - if not you can use `namespace_name::test_class`, as long as the namespace was declared, or simply `friend class test_class` if `test_class` is located in the same namespace.) – Qwertie Nov 23 '18 at 02:35
  • Although this method works fine, I personally don't want to 'pollute' my code with test related stuff. – Erik Bongers Apr 15 '22 at 20:52
22

I know this is an older question, but it seems that nobody has shared the relatively good method that I prefer, so here it goes:

Change the method you wish to test from private to protected. For other classes, the method is still going to be private, but now you can derive a "testing" class from your base class that exposes the private functionality you want tested.

Here's a minimal example:

class BASE_CLASS {
  protected:
    int your_method(int a, int b);
};

class TEST_CLASS : public BASE_CLASS {
  public:
    int your_method(int a, int b) {
      return BASE_CLASS::your_method(a, b);
    }
}

Of course you will have to update your unit tests to run your tests on the derived class instead of the base class, but after that, any change made to the base class will be automatically reflected in the "testing" class.

Miloš
  • 221
  • 2
  • 3
  • 1
    I've just come to the conclusion that this is the only way to do the test. It feels a little bit weird to do this though because when I think of access specifiers I think about access for production code and not testing code. Ideally I'd like it if there were keywords "testably_protected" and "testably_private" or something of the sort. –  Sep 20 '17 at 16:26
  • 6
    Changing private to protected modifies the encapsulation of the class. If you make your test fixture a friend, it gets the access it needs, but no else does. – Aaron Swan Aug 29 '18 at 23:01
9

After many hours this is what I decided to be the best solution for ones that want to test their private functions. This is combination of answers by Max DeLiso and Miloš.

If you are using boost::unit-test then there's an easy and elegant solution.

  1. Use protected instead of private in your classes

    /* MyClass.hpp */
    
    class MyClass {
    
    protected:
        int test() {
            return 1;
        }
    };
    
  2. Create a fixture:

    /* TestMyClass.cpp */
    
    class F : public MyClass {};
    
    
    BOOST_FIXTURE_TEST_SUITE(SomeTests, F)
    
    // use any protected methods inside your tests
    BOOST_AUTO_TEST_CASE(init_test)
    {
        BOOST_CHECK_EQUAL( test(), 1 );
    }
    BOOST_AUTO_TEST_SUITE_END()
    

This way you can freely use any of the MyClass functions without #define private public or adding friends to you class!

Pari
  • 458
  • 2
  • 6
  • 15
  • This is by far the nicest solution. I would upvote this 10 times if I could. Thanks! –  Nov 06 '17 at 20:44
  • 4
    it doesn't work with private. and making private protected just for unit test seems absurd. – bugs king Apr 20 '18 at 02:16
  • @bugsking, agreed. Also, it's even worse than having that define, because at least that define can be deleted, while for this solution you have to change the whole code. And the scopes should never depend on whether you are testing your code or not. – guilhermemtr Jul 28 '18 at 16:29
5

The define hack is a horrible idea. Arbitrarily re-writing your code with the preprocessor when you go to compile it is never wise.

Now as several people have mentioned already, it's debatable whether you should be testing private methods at all. But this doesn't cover the case where you've intentionally hidden constructors to restrict instantiaton to certain scopes, or a few other more esoteric cases.

Also, you can't friend a namespace and "friendship" is not inherited in C++ so depending on your unit testing framework you could be in trouble. Luckily, if you're using Boost.Test, there's in elegant solution to this issue in the form of Fixtures.

http://www.boost.org/doc/libs/1_52_0/libs/test/doc/html/utf/user-guide/fixture/per-test-case.html

You can friend the fixture and have it instantiate all of the instances that you use in your unit testing functions, declaring them as static to the fixture and with module scope. If you're using a namespace don't worry, you can just declare your fixture within the namespace and your test cases outside of the namespace, and then use the scope resolution operator to get to the static members.

The BOOST_FIXTURE_TEST_CASE macro will take care of instantiating and tearing down your fixture for you.

Max DeLiso
  • 1,213
  • 11
  • 23
  • What do you mean "friend the fixture"? How do you do that? Also, does it need to be within a BOOST_FIXTURE_TEST_SUITE? Trying to do that results in all BOOST_AUTO_TEST_CASES within failing to compile. – Tyler Shellberg Nov 07 '21 at 21:26
  • Sidenote, the link also says "You can't access private members of fixture" – Tyler Shellberg Nov 07 '21 at 21:33
-1

I don't think unit test cases would be required for private methods.

If a method is private it can used only within that class. If you have tested all the public methods using this private method then there is no need to test this separately since it was used only in those many ways.

aeh
  • 779
  • 5
  • 8
  • 5
    Nope. Imagine you have a class with public interface and a private method sum(). You write it up, your public interface unit tests all pass. Months go by, someone makes a change to sum that introduces a bug without breaking the public interface unit tests. The public interface is a level of abstraction away from sum(). The further away you are in abstraction, the harder to fully test. Just because the public interface seems to work doesn't mean there are bugs in there that you don't want to catch. – iheanyi Apr 21 '14 at 15:37
  • 3
    So, rather than write a million unit test of the public interface so that you exercise everything behind it in all ways possible, why don't you just write a smaller number of tests for each function and a smaller number for the public interface? – iheanyi Apr 21 '14 at 15:40
  • @iheanyi If the tests of the public methods, which make use of `sum()`, don't break with the change, why do you expect the unit test of `sum()` itself to break? – Kyle Strand Apr 15 '15 at 17:14
  • @KyleStrand Easy. Let's say sum() does the following: temp = x + A; result = A + y. You write a unit test to verify that temp and result are computed correctly. I change sum() to instead to: temp = y + A; result = A + x; Unit test breaks, public interface still works. This is a trivial example but shows how brittle a unit test can be when it is tightly coupled to private implementation. – iheanyi Apr 15 '15 at 18:04
  • @KyleStrand The public interface is sort of a contract. You can be reasonably sure it won't change. There is no guarantee about anything in the private interface. It can change drastically and still achieve the exact same behavior promised by the public interface. Writing unit tests that are coupled to the private methods/variables is useless. You'd need to change them every time the private stuff changes so your tests only reflect the current behavior of the system. They won't bugs you introduce because you modified them to be compatible with buggy code. – iheanyi Apr 15 '15 at 18:08
  • @KyleStrand If unit tests were coupled to private implementation, each time you make a change to the private side, you must change unit tests. Your unit tests just become an exercise in writing the same code twice and you've subverted the purpose of unit tests. Unit tests should ensure the behavior promised by the public interface actually works and should catch bugs introduced by refactoring the private implementation. If your unit tests depend on private implementation, they cannot catch such bugs and they don't actually test the public interface. – iheanyi Apr 15 '15 at 18:11
  • @iheanyi I'm somewhat confused. Your initial comment that I was responding to seems to be saying that you *do* need unit tests for private functions ("Just because the public interface seems to work..."). But your statement that "Writing unit tests that are coupled to the private methods/variables is useless", and the rest of your comments in response to me, seem to indicate that you actually agree with my point that a unit test for the private function `sum()` won't necessarily be helpful in catching bugs. – Kyle Strand Apr 15 '15 at 19:46
  • 1
    @KyleStrand Yes, rereading my original comment, it appears that it was written before I had a better understanding of unit tests. Then, seeing your comment almost a year later, I incorrectly construed it to contradict my current view, w/o realizing (or reading to discover) that my original comment also contradicts my current view! I'm sorry for the confusion. Its not everyday one runs into such concrete evidence of past misunderstandings :) – iheanyi Apr 15 '15 at 20:44
  • 2
    @iheanyi Well, uh, drinks all around, then! – Kyle Strand Apr 15 '15 at 21:09