0

I want to test a public method that calls multiple private methods. What I read from all the answers to previously asked questions are varying. Some say if one encounters such situation, then probably the structure is wrong, or methods that call other methods without any logic should not be tested, etc.

What is not clear for me is that, should I mock these private methods (using PowerMock or any reflection based library) and unit test just this method, or should I provide different types of inputs, so that all the cases will be tested, but private methods will be invoked as well. In the latter case, is it gonna be unit testing still, since I will call other methods, as well.

class ClassToTest {

    public void publicMethod (Argument argument) {
        try {
            privateMethod1();

            privateMethod2(argument);

            privateMethod3();
        } catch (Exception ex) {
            privateMethod4();
        }
    }

}
Mansur
  • 1,661
  • 3
  • 17
  • 41
  • 1
    Closely related: https://stackoverflow.com/q/7075938/2422776 – Mureinik Jun 19 '19 at 05:33
  • 2
    The latter. Don't even try to mock private methods. And yes, it's still unit testing. – Dawood ibn Kareem Jun 19 '19 at 05:34
  • One question, most people say private method mocking/invocation using reflection is a terrible idea when it comes to unit testing. How about setting private field values through reflection? Is it still "unacceptable"? – Mansur Jun 19 '19 at 07:34

1 Answers1

1

First, it is important to understand that attempts to keep unit-test suites completely independent of implementation details is likely to result in inefficient test suites - that is, test suites that are not suited to find all bugs that could be found. And, finding bugs is one primary goal of testing (see Myers, Badgett, Sandler: The Art of Software Testing, or, Beizer: Software Testing Techniques, and many others).

Alternative implementations of the same interface have different potential bugs. Tests for an iterative / recursive implementation of the fibonacci function will look different than for an implementation using the closed-form-expression from Moivre/Binet, or for a lookup-table implementation.

There are, however, also secondary goals of unit-testing. One of them is to avoid that your tests break unnecessarily when implementation details change. Therefore, a test should not unnecessarily depend on implementation details. Always try first to create useful tests that are implementation agnostic, and later add the tests that are implementation specific. For the latter, testing internal (private) methods (for example by making them package visible) can also be a valid option - as long as you are aware of the disadvantages (test code maintenance will be needed if internal methods are renamed, deleted etc.) and weigh them against the advantages.

Second, very likely you should not mock the private methods, but just use them as part of their tests. I say very likely, because it depends on the methods. Mocking should be done for a reason (and avoided otherwise). Good reasons are:

  • You can not easily make the depended-on-component (DOC) behave as intended for your tests.
  • Does calling the DOC cause any non-derministic behaviour (date/time, randomness, network connections)?
  • The test setup is overly complex and/or maintenance intensive (like, need for external files)
  • The original DOC brings portability problems for your test code.
  • Does using the original DOC cause unnacceptably long build / execution times?
  • Has the DOC stability (maturity) issues that make the tests unreliable, or, worse, is the DOC not even available yet?

For example, you (typically) don't mock standard library math functions like sin or cos, because they don't have any of the abovementioned problems. You will have to judge whether this also holds for your private methods.

Dirk Herrmann
  • 5,550
  • 1
  • 21
  • 47
  • Thank you so much Dirk, I got the point. The second bullet point was the one I needed. My private methods behave in a deterministic way, based on the input provided there's only one returned value. But one question, most people say private method mocking/invocation using reflection is a terrible idea when it comes to unit testing. How about setting private field values through reflection? Is it still "unacceptable"? – Mansur Jun 20 '19 at 05:08
  • 1
    As mentioned in my answer, any dependency on implementation details comes at the price of more fragile tests. The benefit can outweigh this price, so I would not generally say it is "unacceptable". You can often reduce risks by hiding ugliness behind helper methods. On the other hand, helper methods may also be an option to factor out complex setups via the public API and thus stay on the cleaner side. However, what is right for situation A can be wrong for situation B - it's all about situation specific tradeoffs. – Dirk Herrmann Jun 20 '19 at 19:11