Can we changed the access specifier of a method from private to default just for the sake of method level unit testing

781 Views Asked by At

I could find many questions/answers on why a method should not make it public. but I could not find anything specific to "default" in Java.

2

There are 2 best solutions below

0
JeroenHoek On BEST ANSWER

'default', i.e., the absence of a modifier, means package private in Java. Only classes in the same package can access it. Sometimes it is desirable to test an internal method meant for private use of that class in a unit test separate from the rest of that class in order to cover all code paths with clear, concise, and simple tests. When you do this (and the result is cleaner test code that can be maintained with more ease) it is fine to mark that method as package private.

This is not an uncommon strategy. Because the only classes who can use this method must reside in the same package, you still have plenty of control over its use.

Personally I would recommend only doing this for static utility methods that do not depend on the state of their parent class. It is also a very useful technique for testing static methods in abstract classes.

Note that in some cases the need to test private methods may point to the need to break out that part of the class into a separate class instead. This discussion shows some of the common standpoints varying from strict OOP adherence to pragmatism. You often have the possibility to break out that method and make it into a proper public static utility, but that doesn't always make sense, and it doesn't necessarily lead to easier maintained code.

0
Timothy Truckle On

UnitTests are not about testing code, they are about testing public observable behavior, that is: return values and communication with dependencies.

Public observable does not necessarily imply public methods but usually is. We simply test the Methods that other code would call when using the current unit as dependency.

Non public methods (that are not meant to be called by other code) are implementation detail that contributes to the units behavior. Therefore they are testes implicitly.

Keep in mind, that a unit is not connected to a class or a method. It might even be a group of classes behind a single class acting as "entry point". A unit is all the code that may change for the same (non technical) reason, a change in the business requirements.

The point here is that implementation details may change while the desired behavior (and thus the UnitTest) does not change. We do such changes to improve the code design (resolve code duplication, apply design patterns and alike). We call them refactoring (This is the third phase in the Test Driven Developement micro cycle). Such a refactoring is exactly the time when we need UnitTest most since when we not change them then they guarantee that the desired behavior of the tested code still exist.