Java tool for testing private methods?

There are different opinions on the importance of testing private methods, for example here and here . I personally think that this makes sense, the question is how to do it right. In C ++ you can use #define to hack or make a test friend class, in C # there is an InternalsVisibleToAttribute , but in Java we either need to use reflection , or make them "visible for testing" and annotate them as such to make it clear. The flaws of both should be clear enough.

I think there should be something better. Beginning with

 public class Something { private int internalSecret() { return 43; } } 

it would be nice to be able to call private methods in test code, for example

 @MakeVisibleForTesting Something something = new Something(); Assert.assertEquals(43, something.internalSecret()); 

Here, the annotation tacitly converts all calls to private something methods using reflection. I wonder if Lombok can (and ask the authors).

It is possible that the execution of this magic turned out to be too complicated, and in any case it will take some time, so I am looking for an alternative. Perhaps annotating the test class with something like @Decapsulate and using the annotation handler to create the Decapsulated_Something class, similar to

 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 working with annotation processing, so I ask first:

  • How hard is it to implement this?
  • What did I forget?
  • What do you think of this in general?
+7
source share
5 answers

it would be nice to be able to call private methods in test code, for example

 @MakeVisibleForTesting Something something = new Something(); Assert.assertEquals(43, something.internalSecret()); 

There is such a thing as a method annotation, check dp4j @TestPrivates :

 @Test @TestPrivates //since the method is annotated with JUnit @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] } 
+1
source

It seems to be very difficult for this implementation. Maybe it's not worth it. Rather, just make the default method package.

However, if you are set up to call a private method, you can use setAccessible in your Decapsulated_something class to resolve the call through reflection, so it's pretty simple.

+7
source

I will answer the question “In general” :-) In order to make the method accessible through reflection, it takes only a few lines of code, and there are many libraries, utils, APIs, etc. that provide methods for this, It’s also possible There are many different methods that you could use in your own code. For example, bytecode manipulation, reflection, class extensions, etc. But I would be inclined to keep things simple. Although this may be useful for testing private methods, it is also likely that you want to test only some of them. So engineering something complicated is probably too big. I would just use the installed API or write a quick method to access the private methods that interest me, and let it be done.

+1
source

There are several approaches to using

  • Do not test personal methods, as they are hidden implementation details that should never affect the caller.
  • Make local methods local so that the caller cannot access them, but you can access them in the same package, i.e. unit test.
  • Do a unit test inner class or provide a local inner package class. Not sure if this is an improvement!
  • Use reflection to access class methods. This is similar to marking the rpivate method when it is not there and this is IMHO confusion. You should only mark the private method when it is truly private.
+1
source

I worked on a project for several years that created classes to simplify private unit test methods. http://java.net/projects/privateer/

It generated additional classes that made it simpler than a reflection call, for example. if you have MyClass.myPrivateMethod (), it will generate the _MyClass class, which allows you to directly call myPrivateMethod.

It was never really finished and was useful for several cases, but in general I would not recommend testing private methods if it is absolutely necessary. Usually redesigning them into utility classes (with access to packages if you are worried about users using them) is the best option.

+1
source

All Articles