2

We are maintaining some legacy code and we are adding tests for them.

In order to write tests easier, we will extract some code into methods(which will be private be default), then writing tests for them. Since they are private, it's hard to invoke them, so what we did is: remove the "private" keyword, make it "non-private", then write tests.

But it makes some methods non-private which are supposed to be "private". Is it OK to do this, or is there any better solutions?


Update:

I think I'd better to provide some more background:

The code is very complicated and not good, and has nearly no tests. Writing tests for public methods are not possible since they have lots of hard-coded external dependencies and which are not be mocked.

We need to fix some bugs, but without tests we can't do it. So we first extract some related code to some methods, add tests for them, then fix bugs.

Since the extracted methods are private by default, we have to make them non-private, otherwise we have to invoke them by reflection:

Method method = Somecls.class.getMethod("a-private-method");
method.setAccessible(true);
method.invoke(...)

But if we make it non-private, we can just:

Somecls cls = new Somecls();
cls.nonPrivateMethod(...)
Freewind
  • 193,756
  • 157
  • 432
  • 708
  • Methods that are `private` are implementation details. The best tests test the interface (i.e., the `public` methods intentionally exposed to other classes); for the most part, all that really matters is that the implementation behaves according to the promise of the interface. That said, if your `public` methods are so complicated that they need to be broken into many `private` methods and tested individually from there, this could be a design smell and you should reexamine the design. – Platinum Azure Nov 23 '13 at 15:45
  • 5
    Several good answers here: http://stackoverflow.com/questions/6913325/annotation-to-make-a-private-method-public-only-for-test-classes – jaco0646 Nov 23 '13 at 16:04
  • If you want your code to be testable you have to break dependencies first. Then testing the public interface methods becomes possible (and a piece of cake sometimes). – Behe Nov 23 '13 at 16:06

3 Answers3

3

If the method is private, then it will be invoked by a public method in that class. Ideally, the test cases should pass through the public method to reach all the possible flows in that private method.

Karthik
  • 1,005
  • 8
  • 7
  • I believe that it's sometimes necessary to test both methods in order to have full test coverage of the class. – Hiro2k Nov 23 '13 at 16:03
1

I think this is something pretty personal. In most of the scenarios I don't see any harm on changing the scope of a method from private to protected/package private if this helps to write better unit tests. It not only allows to invoke the method from your test - which you might do either way using reflection -, but also to override/mock that method when testing another one invoking this.

However, if you don't want to do it you still can use tools like Spring's ReflectionTestUtils to make the invocation of private methods less painful.

diegomtassis
  • 3,557
  • 2
  • 19
  • 29
0

Yes this is perfectly acceptable for creating unit tests for the private methods. By leaving out the private keyword you create what is a known as a package-private method which can only be accesed by other classes that are in the same package. This lets you create unit test classes in the same package that can call your methods but also provides encapsulation so clients that use your class can't call those methods.

Hiro2k
  • 5,254
  • 4
  • 23
  • 28