Update:
Some 10 years later perhaps the best way to test a private method, or any inaccessible member, is via @Jailbreak
from the Manifold framework.
@Jailbreak Foo foo = new Foo();
// Direct, *type-safe* access to *all* foo's members
foo.privateMethod(x, y, z);
foo.privateField = value;
This way your code remains type-safe and readable. No design compromises, no overexposing methods and fields for the sake of tests.
If you have somewhat of a legacy Java application, and you're not allowed to change the visibility of your methods, the best way to test private methods is to use reflection.
Internally we're using helpers to get/set private
and private static
variables as well as invoke private
and private static
methods. The following patterns will let you do pretty much anything related to the private methods and fields. Of course, you can't change private static final
variables through reflection.
Method method = TargetClass.getDeclaredMethod(methodName, argClasses);
method.setAccessible(true);
return method.invoke(targetObject, argObjects);
And for fields:
Field field = TargetClass.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);
Notes:
1. TargetClass.getDeclaredMethod(methodName, argClasses)
lets you look into private
methods. The same thing applies for
getDeclaredField
.
2. The setAccessible(true)
is required to play around with privates.
Yay! Now it's testable; I can feed in test doubles (mocks) to the DoIt method. But at what cost? I've now had to define 3 new interfaces just to make this testable. And what, exactly, am I testing? I'm testing that my DoIt function properly interacts with its dependencies. It doesn't test that the zip file was unzipped properly, etc.
You have hit the nail right on its head. What you want to test is the logic of your method, not necessarily whether a true file can be addressed. You don´t need to test (in this unit test) whether a file is correctly unzipped, your method takes that for granted. The interfaces are valuable by itself because they provide abstractions that you can program against, rather than implicitly or explicitly relying on one concrete implementation.
Best Answer
I'm with you, even though it's a good goal to "only unit test the public API" there are times when it doesn't seem that simple and you feel you are choosing between compromising either the API or the unit-tests. You know this already, since that's exactly what you're asking to do, so I won't get into it. :)
In TypeScript I've discovered a few ways you can access private members for the sake of unit-testing. Consider this class:
Even though TS restricts access to class members using
private
,protected
,public
, the compiled JS has no private members, since this isn't a thing in JS. It's purely used for the TS compiler. Therefor:You can assert to
any
and escape the compiler from warning you about access restrictions:The problem with this approach is that the compiler simply has no idea what you are doing right of the
any
, so you don't get desired type errors:This will obviously make refactoring more difficult.
You can use array access (
[]
) to get at the private members:While it looks funky, TSC will actually validate the types as if you accessed them directly:
To be honest I don't know why this works.This is apparently an intentional "escape hatch" to give you access to private members without losing type safety. This is exactly what I think you want for your unit-testing.Here is a working example in the TypeScript Playground.
Edit for TypeScript 2.6
Another option that some like is to use
// @ts-ignore
(added in TS 2.6) which simply suppresses all errors on the following line:The problem with this is, well, it suppresses all errors on the following line:
I personally consider
@ts-ignore
a code-smell, and as the docs say: