15

I know that this is a debated practice, but let's suppose that this is the best option for me. I am wondering about what is the actual technique to do this. The approach that I see is this:

1) Make a friend class that of the class who's method I want to test.

2) In the friend class, create a public method(s) that call the private method(s) of the tested class.

3) Test the public methods of the friend class.

Here is a simple example to illustrate the above steps:

#include <iostream>

class MyClass
{
  friend class MyFriend; // Step 1

  private:
  int plus_two(int a)
  {
    return a + 2;
  }
};

class MyFriend
{
public:
  MyFriend(MyClass *mc_ptr_1)
  {
    MyClass *mc_ptr = mc_ptr_1;
  }

  int plus_two(int a) // Step 2
  {
    return mc_ptr->plus_two(a);
  }
private:
  MyClass *mc_ptr;
};

int main()
{
  MyClass mc;
  MyFriend mf(&mc);
  if (mf.plus_two(3) == 5) // Step 3
    {
      std::cout << "Passed" << std::endl;
    }
  else
    {
      std::cout << "Failed " << std::endl;
    }

  return 0;
}

Edit:

I see that in the discussion following one of the answers people are wondering about my code base.

My class has methods that are called by other methods; none of these methods should be called outside the class, so they should be private. Of course they could be put into one method, but logically they are much better separate. These methods are complicated enough to warrant unit testing, and due to performance issues I will very likely have to re-factor these methods, hence it would be nice to have a test to make sure that my re-factoring didn't break anything. I am not the only one working on the team, though I am the only one who is working on this project including the tests.

Having said the above, my question was not about whether it is a good practice to write unit tests for private methods, though I appreciate the feedback.

  • 5
    Here's a questionable suggestion for a questionable question. I don't like the coupling of friend as then released code has to know about the test. Nir's answer below is one way to alleviate that, but I still don't much like changing the class to conform to the test. Since I don't rely on inheritance often, I sometimes just make the otherwise private methods protected and have a test class inherit and expose as needed. I expect at least three "boo hisses" for this comment, but the reality is that the public API and the testing API can differ and still be distinct from the private API. Meh. – J Trana Oct 1 '14 at 3:27
  • 4
    @JTrana: Why not write that up as a proper answer? – Bart van Ingen Schenau Oct 1 '14 at 5:06
  • Ok. This is not one of those ones you feel super-proud about, but hopefully it will help. – J Trana Oct 2 '14 at 1:19
21

An alternative to friend (well, in a sense) that I use frequently is a pattern that I've come to know as access_by. It's pretty simple:

class A {
  void priv_method(){};
 public:
  template <class T> struct access_by;
  template <class T> friend struct access_by;
}

Now, suppose class B is involved in testing A. You can write this:

template <> struct access_by<B> {
  call_priv_method(A & a) {a.priv_method();}
}

You can then use this specialization of access_by to call private methods of A. Basically, what this does is put the onus of declaring friendship into the header file of the class that wants to call A's private methods. It also lets you add friends to A without changing A's source. Idiomatically, it also indicates to whoever reads the source of A that A does not indicate B a true friend in the sense of extending its interface. Rather, the interface of A is complete as given and B needs special access into A (testing being a good example, I've also used this pattern when implementing boost python bindings, sometimes a function that needs to be private in C++ is handy to expose into the python layer for the implementation).

9

If it's hard to test, it's badly written

If you have a class with private methods complex enough to warrant their own test, the class is doing too much. Inside there is another class trying to get out.

Extract the private methods that you want to test into a new class (or classes) and make them public. Test the new classes.

In addition to making the code easier to test, this refactoring will make the code easier to understand and maintain.

  • 1
    I completely agree with this answer, if you can't test your private methods completely by testing the public methods, something is not right and refactoring the private methods to their own class would be a good solution. – David Perfors Oct 2 '14 at 10:59
  • 2
    In my codebase, a class has a very complex method that initializes a computational graph. It calls several sub-functions in sequence to achieve various aspects of this. Each sub-function is quite complicated, and the sum total of the code is very complicated. However, the sub-functions are meaningless if not called on this class and in the right sequence. All the user cares about is the computational graph being fully initialized; the intermediates are worthless to the user. Please, I'd like to hear how I should refactor this, and why it makes more sense than just testing the private methods. – Nir Friedman Oct 2 '14 at 19:50
  • 1
    @Nir: Do the trivial: extract a class with all those methods public, and make your existing class a facade around the new class. – kevin cline Oct 2 '14 at 21:36
  • This answer is correct but it really depends on the data you are working with.In my case I am not provided with actual testing data so I have to create some by observing real time data and then "inject" it into my application and see how it goes.A single piece of data is too complex to handle so it would be much easier to artificially create partial testing data that is only a subset of the realtime data to target each than actually reproduce the realtime data.The private function are not complex enough to call for implementation of several other small class (with the respective functionality) – rbaleksandar Feb 8 '18 at 9:13
4

You shouldn't be testing private methods. Period. The classes using your class only care about the methods that it provides, not the ones it uses under the hood to work.

If you're worrying about your code coverage, you need to find configurations that allow you to test that private method from one of the public method calls. If you can't do that, what's the point of having the method in the first place? It's simply unreachable code.

  • 6
    The point of private methods is to ease development (through seperation of concerns, or maintaining DRY, or any number of things) but are meant to be non permanent. They are private for that reason. They could appear, disappear, or change in functionality drastically from one implementation to the next, which is why tying them to unit tests is not always practical, or even useful. – Ampt Oct 1 '14 at 1:02
  • 8
    It may not always be practical or useful, but that's a very far cry from saying that you should never be testing them. You are talking about the private methods as though they are somebody else's private methods; "they could appear, disappear...". No, they could not. If you are unit testing them directly, it should only be because you maintain them yourself. If you change the implementation, you change the tests. In short, your blanket statement is unjustified. While it's good to warn the OP about this, his question is still justified, and your answer doesn't actually answer it. – Nir Friedman Oct 1 '14 at 1:10
  • 2
    Let me also note: the OP said up front he's aware that it's a debated practice. So if he wants to do it anyway, maybe he really does have good reasons for it? Neither of us know the details of his codebase. In the code I work with, we have some very experienced and expert programmers, and they thought it was useful to unit test private methods in some cases. – Nir Friedman Oct 1 '14 at 1:16
  • 2
    -1, an answer like "You shouldn't be testing private methods." is IMHO not helpful. The topic when to test and when not to test private methods has been discussed on this site sufficiently. The OP has shown that he is aware of this discussion, and its clearly he is looking for solutions under the assumption that in his case testing private methods is the way to go. – Doc Brown Oct 1 '14 at 5:53
  • 3
    I think the problem here is that this may be a very classic XY Problem in that OP thinks he needs to unit test his private methods for one reason or another, when in reality he could approach the testing from a more pragmatic viewpoint, viewing the private methods as mere helper functions for the public ones, which are the contract with the end users of the class. – Ampt Oct 1 '14 at 13:51
3

There are a few options to do this, but keep in mind that they (in essence) modify the public interface of your modules, to give you access to internal implementation details (effectively transforming unit testing into tightly coupled client dependencies, where you should have no dependencies at all).

  • you could add a friend (class or function) declaration to the tested class.

  • you could add #define private public to the beginning of your test files, before #include-ing the tested code. In case the tested code is an already-compiled library though, this could make the headers no longer match already compiled binary code (and cause UB).

  • you could insert a macro in your tested class and decide at a later date what that macro means (with a different definition for testing code). This would allow you to test internals, but it would also allow third party client code to hack into your class (by creating their own definition in the declaration you add).

2

Here's a questionable suggestion for a questionable question. I don't like the coupling of friend as then released code has to know about the test. Nir's answer is one way to alleviate that, but I still don't much like changing the class to conform to the test.

Since I don't rely on inheritance often, I sometimes just make the otherwise private methods protected and have a test class inherit and expose as needed. The reality is that the public API and the testing API can differ and still be distinct from the private API, which leaves you in sort of a bind.

Here's a practical example that's of the sort I resort to this trick for. I write embedded code, and we rely on state machines quite a bit. The external API doesn't necessarily need to know about the internal state machine state, but the test should (arguably) test conformance to the state machine diagram in the design doc. I might expose a "current state" getter as protected and then give the test access to that, allowing me to test the state machine more fully. I often find this type of class hard to test as a black box.

  • While it is a Java approach, this is quite standard to make private functions default level instead allowing other classes in the same package (the test classes) to be able to see them. – user40980 Oct 2 '14 at 1:31
0

You can write your code with lots of workarounds to stop you having to use friends.

You can write classes and never have any private methods at all. All you need to then do is make implementation functions within the compilation unit, let your class call them and pass in any data members they need to access.

And yes it will mean you can change the signatures or add new "implementation" methods without changing your header in the future.

You have to weigh up though whether or not it is worth it. And a lot will really depend on who is going to see your header.

If I'm using a 3rd party library I'd rather not see friend declarations to their unit testers. I don't want to build their library either and have their tests run when I do. Unfortunately too many 3rd party open source libraries I have built do that.

Testing is the job of the writers of the library, not its users.

However not all classes are visible to the user of your library. Lots of classes are "implementation" and you implement them the best way to ensure they work properly. In those, you may still have private methods and members but want unit testers to test them. So go ahead and do it that way if that will lead to robust code quicker, that is easy to maintain for those who need to do so.

If the users of your class are all within your own company or team, you can also relax a bit more about that strategy, assuming it's allowed by your company's coding standards.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.