I very often hear the following: "If you want to test private methods, you'd better put that in another class and expose it."

While sometimes that's the case and we have a hiding concept inside our class, other times you end up with classes that have the same attributes (or, worst, every attribute of one class become a argument on a method in the other class) and exposes functionality that is, in fact, implementation detail.

Specially on TDD, when you refactor a class with public methods out of a previous tested class, that class is now part of your interface, but has no tests to it (since you refactored it, and is a implementation detail).

Now, I may be not finding an obvious better answer, but if my answer is the "correct", that means that sometimes writting unit tests can break encapsulation, and divide the same responsibility into different classes.

A simple example would be testing a setter method when a getter is not actually needed for anything in the real code.

Please when aswering don't provide simple answers to specific cases I may have written. Rather, try to explain more of the generic case and theoretical approach. And this is neither language specific.

Thanks in advance.

EDIT: The answer given by Matthew Flynn was really insightful, but didn't quite answer the question. Altough he made the fair point that you either don't test private methods or extract them because they really are other concern and responsibility (or at least that was what I could understand from his answer), I think there are situations where unit testing private methods is useful. My primary example is when you have a class that has one responsibility but the output (or input) that it gives (takes) is just to complex. For example, a hashing function. There's no good way to break a hashing function apart and mantain cohesion and encapsulation. However, testing a hashing function can be really tough, since you would need to calculate by hand (you can't use code calculation to test code calculation!) the hashing, and test multiple cases where the hash changes. In that way (and this may be a question worth of its own topic) I think private method testing is the best way to handle it. Now, I'm not sure if I should ask another question, or ask it here, but are there any better way to test such complex output (input)?

OBS: Please, if you think I should ask another question on that topic, leave a comment. :)

EDIT2: I accepted a answer as my correct because it made me think and decide my course of action, altough it didn't answered my queston completely. But for those who face the same problem as I do (one cohesive class that will change together, but is still too hard to test by itsfelf), I'll tell what I did and why. I decided that the output of that class is simply too hard to a computer to test correctly, so I didn't test it. I could have used a framework to test it's private methods (which would be the best idea, I think), but I didn't want to get to that point. If you are wondering what it is that is cohesive and respects SRP, and still is too hard to a computer to test, I'll give some examples: heightmap generation, hashing functions, procedural music generation (you can test some units, but the highest level unit is simply too subjective).

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

2

Some unit testing frameworks allow the use of a proxy class that can access the internal methods of a type. You can unit test your private methods, while still benefiting from encapsulation.
–
Robert HarveyOct 21 '12 at 0:52

5 Answers
5

When I was younger and raised this question, I was told that I really don't need to write unit tests for private methods. Surprisingly, this turned out to be true.

If you take a behavioral driven approach to unit tests, this makes perfect sense--your public methods are what are being asked to do stuff. The fact that they call internal private methods is orthogonal to their outward behavior. Because the other method is private/encapsulated, it really is part of the unit being tested.

You may ask that if multiple methods in your class all call a single private method, so shouldn't you be testing that that one method works? The answer here is yes, but it is not made evident by a unit test of the private method, but rather the unit tests of the public methods calling it. If the public methods work, and they call a private method, then the private method must also work.

All true, but there is a genuine benefit to testing internal methods, if an internal method is what is desired. If it's worthwhile refactoring the functionality into a separate method containing any significant functionality, it's also worth writing tests for that method.
–
Robert HarveyOct 21 '12 at 1:35

1

Consider now a class that encapsulates a complex behavior (albeit still one responsibility and still cohesive). In that case, it might be simple to test the steps required to complete the task, rather than the task itself.
–
user1288851Oct 21 '12 at 1:41

2

@user1288851 - Is that a hypothetical question, or do you have an example where a cohesive, single-responsibility-containing class contains such complex behavior that you can't easily test its public methods to determine its correctness?
–
Matthew FlynnOct 21 '12 at 2:23

2

@RobertHarvey - You ARE testing that method, just indirectly through the methods you are refactoring (whose correctness is what really matters).
–
Matthew FlynnOct 21 '12 at 2:25

3

Nice answer. I'd just like to add to those who say complex private methods need unit tests: that could be an indication that those methods -- or parts of them -- should be refactored to be public methods of a different class, allowing them to be tested independently without polluting the interface of the original class.
–
user39685Nov 6 '12 at 12:59

When you feel the urge to test private methods, you're simply doing it wrong. It might be okay to factor out a complicated algorithm of a private method to a separate, "more public" class, and use this class in the original private method. But the point is this still doesn't break encapsulation.

If you make something private, it is not part of the API of the class, it just doesn't exist for the outside world. If something happens there which is really important, and should be tested in your opinion, but can't be properly detected through the API, then something in your API design is broken. You have to decide if something matters, or if it is an implementation detail. It can't be both.

+1 Factoring class B out of class A doesn't break the encapsulation of the API for A. Clients of A still don't have to know B; you simply added testing for B.
–
Andres F.Oct 21 '12 at 15:35

1

Well, from my perspective it sometimes does. If you are splitting things that change together, thas is a clear violation of SRP. On the other side, if you are splitting two concerns, then you are actually enforcing encapsulation taking the acess of implementation details on B out of A. But it really depends from case to case. My problem is (or was, rather) that if one thing in that class changes, everything in that class needs to change, so it is a cohesive and SRP-friendly class. But it is still too hard to test alone.
–
user1288851Oct 22 '12 at 1:13

Whilst I don't disagree with the answers that say "Private is Private" and in most cases this is true, it isn't always.

If your code product is part of a certificated safety-critical product (eg aerospace, medical, automotive) then you will come across test coverage requirements, and such delights as Modified Condition/Decision Coverage

Saying to the Certification Body that you haven't tested the internals of your class, because private is private will not get you a tick in the box.

Only testing the public interface of a class is Black Box testing... and as long as the results are OK, then (in most cases) that is enough. But sometimes, you need to do White Box testing, and validate the nuts and bolts inside.

I emphasise the sometimes but (as with most "rules") never say "never test the private".

+1. If you don't test it, you may left out the important parts of your code, or test it indirectly, but usually with only a few test values (which usually have no meaning). If a private method is vital to your project, make it public (or protected) and state in the documentation, that it is for testing purposes only. If you design a framework or library, you could put a facade in front of it to protect it from unintentional use.
–
AndyNov 6 '12 at 22:40

First of all, not code, but class behavior is what is tested. Code is just a way to make the class work as expected, but code isn't required at all :) It would be actually better to make your class work without writing code (OFF TOPIC).

Public methods call private methods, so testing public methods should always be enough. When using TDD, you should write tests before the implementation, so it's impossible to test private methods.

As for health-critical software and stuff like that, hitting 100% path coverage by testing private methods will not ensure that tested software works correctly in 100% of cases. You can be sure only after testing all possible input data on all possible object states. Doing this for only public methods should cover all paths in private methods.

There is sometimes value in testing having access to protected/private members.

Suppose you have an initialisation function - you want to test that certain internal variables have been set. The easiest way to do this is for your testing framework to have access to those variables, generally either the testclass derives from the class or there is some trick to convert protected->public during test.

You could add public() functions to return the value of all the protected variables - but that would break encapsulation rather more.

@Kemoda - tests are there to test the implementation. Yes, you can go too far, and having a lot of private access for test code does seem like there may be an interface problem, but it's often easier to make sure you've taken care of all the edge conditions if you have private access in the test code. This is especially true when you have wierd error conditions to deal with - sometimes that stuff is hard to trigger using the normal API.
–
Michael KohneOct 22 '12 at 12:43