What is wrong with making a unit test a friend of the class it is testing? [duplicate]
Asked Answered
A

7

74

In C++, I have often made a unit test class a friend of the class I am testing. I do this because I sometimes feel the need to write a unit test for a private method, or maybe I want access to some private member so I can more easily setup the state of the object so I can test it. To me this helps preserve encapsulation and abstraction because I am not modifying the public or protected interface of the class.

If I buy a third party library, I wouldn't want its public interface to be polluted with a bunch of public methods I don't need to know about simply because the vendor wanted to unit test!

Nor do I want have to worry about a bunch of protected members that I don't need to know about if I am inheriting from a class.

That is why I say it preserves abstraction and encapsulation.

At my new job they frown against using friend classes even for unit tests. They say because the class should not "know" anything about the tests and that you do not want tight coupling of the class and its test.

Can someone please explain these reasons to me more so that I may understand better? I just do not see why using a friend for unit tests is bad.

Arnelle answered 13/11, 2010 at 6:30 Comment(5)
I wonder, if they have introduced some alternatives too?Dewitt
the alternatives was find a way to invoke the method using the public interface; make it protected and extend the class;Arnelle
Not wanting tests to be tightly coupled to the code it tests seems like good intentions gone wrong. Tight coupling between "normal" code is generally something to avoid, but tests are going to be coupled with the code they test by definition.Telegraphone
The duplicate answer is specifically for java.Necessitous
Is there an argument to be made that declaring a friend class leaves open the possibility of misuse by letting someone using your library to define a friend class and alter the internal state of your objects.Totaquine
P
74

Ideally, you shouldn't need to unit test private methods at all. All a consumer of your class should care about is the public interface, so that's what you should test. If a private method has a bug, it should be caught by a unit test that invokes some public method on the class which eventually ends up calling the buggy private method. If a bug manages to slip by, this indicates that your test cases don't fully reflect the contract you wish your class to implement. The solution to this problem is almost certainly to test public methods with more scrutiny, not to have your test cases dig into the class's implementation details.

Again, this is the ideal case. In the real world, things may not always be so clear, and having a unit testing class be a friend of the class it tests might be acceptable, or even desirable. Still, it's probably not something you want to do all the time. If it seems to come up often enough, that might a sign that your classes are too large and/or performing too many tasks. If so, further subdividing them by refactoring complex sets of private methods into separate classes should help remove the need for unit tests to know about implementation details.

Petulia answered 13/11, 2010 at 6:38 Comment(4)
+1 for the hint that too private methods can often be made public in another class.Stalder
I disagree with this. If you're implementing a complex algorithm and want to break it in small steps (that would be completely useless outside of this algorithm's implementation) there is nothing wrong in wanting to keep the steps as a private implementation detail that no other object in the code should be able to access, and still wanting to check that each sub-step returns the correct result given the correct inputs.Kwa
+ 1 for @Jean-MichaëlCelerier . You could have a long a** function which is public or break it down into logical parts. But logical parts don't have to be public. However, they need to be tested. Ex. A transformation of an image where it is warped. Without using libraries that is a long code if not broken into partsNassir
What's the difference between private & public from the perspective of testing? I would say nothing. In fact, I would argue that private functions do the gist of the work, thus generally are precisely what you need to test. Public functions are often just wrappers or in general do mostly trivial things. So I disagree wholeheartedly.Unprejudiced
S
15

You should consider that there are different styles and methods to test: Black box testing only tests the public interface (treating the class as a black box). If you have an abstract base class you can even use the same tests against all your implementations.

If you use White box testing, you might even look at the details of the implementation. Not only about which private methods a class has, but what kind of conditional statements are included (i.e. if you want to increase your condition coverage because you know that the conditions were hard to code). In white box testing, you definitely have "high coupling" between classes/implementation and the tests which is necessary because you want to test the implementation and not the interface.

As bcat pointed out, it's often helpful to use composition and more but smaller classes instead of many private methods. This simplifies white box testing because you can more easily specify the test cases to get a good test coverage.

Stalder answered 13/11, 2010 at 7:53 Comment(0)
H
15

I feel that Bcat gave a very good answer, but I would like to expound on the exceptional case that he alludes to

In the real world, things may not always be so clear, and having a unit testing class be a friend of the class it tests might be acceptable, or even desirable.

I work in a company with a large legacy codebase, which has two problems both of which contribute to making a friend unit-test desirable.

  • We suffer from obscenely large functions and classes which require refactoring, but in order to refactor it is helpful to have tests.
  • Much of our code is dependent on database access, which for various reasons should not be brought into the unit tests.

In some cases Mocking is useful to alleviate the latter problem, but very often this just leads to uneccessarily complex design (class heirarchies where none would otherwise be needed), while one could very simply refactor the code in the following way:

class Foo{
public:
     some_db_accessing_method(){
         // some line(s) of code with db dependance.

         // a bunch of code which is the real meat of the function

         // maybe a little more db access.
     }
}

Now we have the situation where the meat of the function needs refactoring, so we'd like a unit test. It shouldn't be exposed publicly. Now, there's a wonderful technique called mocking that could be used in this situation, but the fact is that in this case a mock is overkill. It would require me to increase the complexity of the design with an unecessary hierarchy.

A far more pragmatic approach would be to do something like this:

 class Foo{
 public: 
     some_db_accessing_method(){
         // db code as before
         unit_testable_meat(data_we_got_from_db);
         // maybe more db code.    
 }
 private:
     unit_testable_meat(...);
 }

The latter gives me all of the benefits I need from unit testing, including giving me that precious safety net to catch errors produced when I refactor the code in the meat. In order to unit test it, I have to friend a UnitTest class, but I would strongly argue that this is is far better than an otherwise useless code heirarchy just to allow me to use a Mock.

I think this should become an idiom, and I think it's a suitable, pragmatic solution to increase the ROI of unit testing.

Hofstetter answered 12/2, 2015 at 13:4 Comment(0)
I
10

Like bcat suggested, as much as possible, you need to find bugs using public interface itself. But if you want to do things like printing private variables and comparing with expected result etc(Helpful for developers to debug the issues easily), then you can make UnitTest class as friend to class to be tested. But you may need to add it under a macro like below.

class Myclass
{
#if defined(UNIT_TEST)
    friend class UnitTest;
#endif
};

Enable flag UNIT_TEST only when Unit testing is required. For other releases, you need to disable this flag.

Isopleth answered 13/11, 2010 at 7:37 Comment(0)
I
6

I don't see anything wrong with using a friend unit testing class in many cases. Yes, decomposing a large class into smaller ones is sometimes a better way to go. I think people are a bit too hasty to dismiss using the friend keyword for something like this - it might not be ideal object oriented design, but I can sacrifice a little idealism for better test coverage if that's what I really need.

Interlocutrix answered 30/12, 2010 at 15:42 Comment(0)
C
2

Typically you only test the public interface so that you are free to redesign and refactor the implementation. Adding test cases for private members defines a requirement and restriction on the implementation of your class.

Coriolanus answered 13/11, 2010 at 17:28 Comment(1)
But a unit test is to test whether your entire class works, not just if the public part of your class works.Unprejudiced
T
0

Make the functions you want to test protected. Now in your unit test file, create a derived class. Create public wrapper functions that call your the class-under-test protected functions.

Trela answered 29/2, 2012 at 15:19 Comment(1)
friend has better encapsulation than protected. By putting the members protected, you give access to all inheriting classes, and implicitly say you will never change them as they are part of the inheriting interface. By putting the members private, and offering friendship to ONE class, you only have an implicit contract with that ONE class. And if that class is a unit-test class, then the contract is not binding.Beore

© 2022 - 2024 — McMap. All rights reserved.