0

I know there is an ongoing debate in many posts [ 1,2 ] in this sites on whether you should test private methods directly or indirectly.
What I can't seem to understand is how can I test a class where it has for example -
3 private methods that are approached by 10 different public methods.

Let's say the private methods sort its specific data structures or retrieve a value from them in a special way that only relates to the class (I am not going to create an inner class in every scenario).

Now, if I choose to test the private indirectly than I would have to re-write the tests for that private logic every time I test the public methods in order to fully test the method and keep the unit tests independent.
(It is not always possible to create a private method in the test class that tests the mutual code )
I will than have a to write repeating code and long test methods.

So how is the indirect testing eligible as a standard?

Community
  • 1
  • 1
Bick
  • 17,833
  • 52
  • 146
  • 251
  • 3
    From [the answer in a thread you linked](http://stackoverflow.com/a/7075965/365237): "the real answer is that if you have the urge to test a private method, the method shouldn't be private; if making the method public bothers you, chances are, it is because it is part of a separate reponsibility; it should be on another class." – eis Oct 01 '14 at 14:52
  • Thanks. But back to my original question: What about if the private method is very simple but yet it is called from multiple public methods. Do I need to refer to the private method logic in most public method tests? Do I write the tests for it only in one (not good)? – Bick Oct 02 '14 at 08:21
  • that is an answer to your original question. You should have tests for all your public methods - if you feel your private method should be tested separately, then it shouldn't be a private method to begin with. – eis Oct 02 '14 at 18:09

3 Answers3

2

In my mind, promoting low coupling and high cohesion on your classes and their methods is by far the most significant contribution of TDD (way more significant than "verifying the code works as intended").

This is not apparent until you force yourself to unit test every method (more or less). Just make the private methods package visible (breaking the encapsulation is justified in this case).

You will soon find that, for instance, it is way easier to test a method that takes an argument and returns something, without relying on (or affecting) the class state otherwise. This is obviously not the case always, but breaking down the concerns enough, you will have more testable (and more readable) code.

Mocking frameworks can be a life saver when the design is strongly coupled to the class state and cannot be de-coupled (this is OK and happens on all imperative languages). You can, for instance, replace the value of a (again package-visible) field with a mock instance before running the test. Make sure to verify the invocations on the mock! Spying can be justified as well, but I personally prefer to use it as a last resort.

In a word, probably. In more words, if writing the tests is hard, think about refactoring the code ;)

dkateros
  • 1,574
  • 10
  • 14
  • Agreed - code that's tough to test is an indicator of potential for refactoring. – TrueDub Oct 01 '14 at 14:50
  • 1
    I'm confused. Are you saying that making the private methods visible to the package is a good idea? Seems like everything else in your answer says 'make the design better' but then says 'just test your private methods'. These are at odds with each other for me, so which one is it :) – Sam Holder Oct 01 '14 at 15:06
  • Striving to test every method will force you to design better (smaller, simpler more focused units not relying on complex states or modifying state in a hard to document and understand manner). In order to actually write the test for a method that is otherwise private (without reflection) it is a common practice to change the visibility of the method to package-visible. – dkateros Oct 02 '14 at 08:24
1

Private methods are an implementation detail. Your tests should focus on either:

  • The externally visible behaviour of your methods
  • The interaction of your class with its dependencies

You should verify all functionality through one of these 2 tactics.

this basically breaks down to this for the first point:

  • If I call method x with arguments y,z then it should return a
  • If I call method x with arguments y,z then when I read property a it should have value b

or this for the second

  • If I call method x with arguments y,z then it should call dependency a with argument y+z

If your tests are of this style then changing the internal implementation will have no effect on the tests (i.e., tests will not be brittle) unless the change is to change the way the class interacts with its dependencies, in which case your tests will have to change anyway.

There should be no reason for you to need to test the internals of a class because if its internals can't be seen either from outside (either directly through reading a property, or indirectly by calling another method with some specific parameters and seeing the result of that method call being affected by the previously created internal state), or from its interaction with its dependencies then it is irrelevant.

Given your specific example it sounds like you have separate responsibilities in play. You have some class with the responsibility for doing the sorting (a Sorter?) which should be a dependency of your main class. You can then test the sorting class independently to verify it does what you expect (type 1 testing above) and then use type 2 testing on this class to ensure that the class calls the Sorter you give it to ensure the elements are sorted correctly.

Breaking things apart in this way not only gives you testability but means you have the potential to reuse the sorter somewhere else.

Sam Holder
  • 32,535
  • 13
  • 101
  • 181
1

I agree with user eis (see comment above) from the answer in a thread you linked:

the real answer is that if you have the urge to test a private method, the method shouldn't be private; if making the method public bothers you, chances are, it is because it is part of a separate reponsibility; it should be on another class.

Try to avoid testing private methods. They should only make the code more readable. If a private method has become so complex that it should be unit tested, extract it into a new class which you can then properly/easily unit test.

Community
  • 1
  • 1
Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • yeah exactly. wanting to test a private method is a helpful signal that something wants to break out of you class. +1 – Sam Holder Oct 01 '14 at 15:03
  • If your goal is code coverage, then just make sure that one of the other tests (for public code) calls it. If your goal is correctness, then it depends on how complex the private code is and whether it's executed by the public API tests. If it's already covered, then you should really treat it as an internal implementation detail. So from a design point of view: Simple private methods -> Low urge to test. Complex private methods -> High urge to refactor and test. – Aaron Digulla Oct 02 '14 at 08:09