3

I'm studing TDD and recently searching for how to unit test private method properly. Popular answers in Stack Overflow were suggesting:

  • Use reflection to make private methods accessable from outside. 1
  • Do not test private methods. (Use public methods instead.) 1 2 3

According to disagreements in comment section, it seems everyone have their own rules. Then I found this tutorial site that suggests a rather bold approach.

  • Make private method protected or package private. Put test codes in the same package.

    Designing for testability means designing your code so that it is easier to test. To do so, you may have to break with some of the principles we learned in university, like encapsulation.

Even though TDD's principle is designing codes for testability, breaking encapsulation for that doesn't sound right for me. Is this approach a good prectice?

Community
  • 1
  • 1
user2652379
  • 782
  • 3
  • 9
  • 27

2 Answers2

3

I think the right answer is: do not test private methods. If you feel the need of testing private methods, probably one of the following two scenarios are happening:

  • the method has not to be private: maybe it's ok that the method could be reached through the API of the object where it resides. In that case, change it to public (or anything else not private). Another option is that you put the behavior of the method inside a public method of another object and you build some dedicated test for it;
  • the method has to be private, so you're testing something that you should not. You are trying to write tests too coupled to the object you're testing. Private methods are not stable by definition, they can change frequently during time. Those changes will break every test that verify directly the private method.
Paolo Laurenti
  • 2,714
  • 2
  • 16
  • 18
  • I don't unit test something too trivial like DTOs. But "you're testing something that you should not" is somewhat new to me. What kind of methods should not be tested? – user2652379 Nov 15 '16 at 00:46
  • Another question. There are still private methods which are complicated enough to be tested. What should I do about that? My thinking is moving the method to a new class if possible and make it public. Maybe there are better approachs? Or there are no workaround and should not test? – user2652379 Nov 15 '16 at 00:55
  • What I mean with "you're testing something that you should not" is that probably you don't need to make a specific test for the logic inside the private method.Maybe you can test the private code by creating a test for a public method that uses that code of the private method. In this way you are effectively testing a public behavior of your object, you're testing some method that is part of the public API and therefore, by definition, it has to be stable. But consequently, you're also testing the private code that needs to be executed in order to satisfy the "public behavior" mentioned above. – Paolo Laurenti Nov 15 '16 at 07:46
  • 1
    As I wrote inside the answer, the private method could be moved in its own object and it can become public. Or you can test the private logic through a test of another public method that uses that logic. Don't think about unit tests as a test per method but try to think about testing in behavior terms. Your tests should verify the behaviors (what the object is able to do, what are the tasks is able to satisfy through is public API) of some object without any knowledge of how that object implements those behaviors. – Paolo Laurenti Nov 15 '16 at 07:56
  • 1
    I think that the following video of Ian Cooper could help you to understand better how to approach this testing problem and how to avoid writing tests too coupled to the code under test: https://vimeo.com/68375232 – Paolo Laurenti Nov 15 '16 at 07:56
0

If you're ok with adding the Guava library as a dependency, you can make the method package private and mark it with the VisibleForTesting annotation.

I'm assuming that you're using Java, though you don't explicitly state that.

Aaron Feldman
  • 474
  • 4
  • 7