There are different opinions on the meaningfulness of testing of private methods, e.g., here and here. I personally think it makes sense, the question is how to do it properly.
In C++ you can use a #define
hack or make the test class friend
, in C# there's the InternalsVisibleToAttribute, but in Java we either have to use reflection or to make them "visible for testing" and annotate them as such in order to make the intent clear. The disadvantages of both should be quite clear.
I think there should be something better. Starting with
public class Something {
private int internalSecret() {
return 43;
}
}
it would be nice to be able to call private methods in the test code like
@MakeVisibleForTesting Something something = new Something();
Assert.assertEquals(43, something.internalSecret());
Here the annotation would silently convert all calls to private methods of something
using reflection. I wonder if Lombok could do it (and will ask the authors).
It's quite possible that doing that much magic proves too complicated, and in any case it'll take some time, so I'm looking for some alternative. Maybe annotating the class under test with something like @Decapsulate
and using an annotation processor to generate a class Decapsulated_Something
looking like
public class Decapsulated_Something {
public Decapsulated_Something(Something delegate) {
this.delegate = delegate
}
public boolean internalSecret() {
// call "delegate.internalSecret()" using reflection
}
...
}
which would allow to use
Decapsulated_Something something = new Decapsulated_Something(new Something());
Assert.assertEquals(43, something.internalSecret());
I don't have much experience with annotation processing, so I ask first here:
It seems like a lot of trouble to do this implementation. It may not be worth it. Rather just make the method package default.
However, if you are determined to call private method, you can use setAccessible in yourDecapsulated_something
class to allow call via reflection. So it's fairly simple.
it would be nice to be able to call private methods in the test code like
@MakeVisibleForTesting Something something = new Something(); Assert.assertEquals(43, something.internalSecret());
There's such thing as a method annotation, check out dp4j's @TestPrivates
:
@Test
@TestPrivates
//since the method is annotated with JUnit's @Test this annotation is redundant.
// You just need to have dp4j on the classpath.
public void somethingTest(){
Something something = new Something();
int sthSecret = something.internalSecret();
Assert.assertEquals(43, sthSecret); //cannot use something.internalSecret() directly because of bug [dp4j-13][2]
}
There are number of approaches to take
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With