Call a static method on a parameter without an instance of the class in the argument

I really got into TDD and I started using mockito in jUnit to improve my ability to test code. I really love mockito!

I noticed that I need to change the way I think about coding, for example, passing as many collaborators as possible to methods and limiting the work that is done in constructors where possible.

The following scenario justified some expert advice here on SO.

Let's say I have a method that will call some static methods for a specific class. For example.

public void method(){ OtherClass.staticMethod(); } 

This is generally bad, but it is necessary in my scenario. To make the code more testable in my unit tests, I would like to avoid dependency on OtherClass and pass it as an argument.

This does not work, as it gives a compile-time error.

 public void method(Class<? extends OtherClass> util){ util.staticMethod(); } ... method(OtherClass.class); 

This will work, but I don't like creating an instance of OtherClass if I don't need it, since this is just a class of static utility, such as methods:

 public void method(OtherClass util){ util.staticMethod(); } ... method(new OtherClass()); 

My question to you is: Is there a preferable way to accomplish this without using a new keyword?

+7
source share
6 answers

This will work, but I don't like creating an instance of OtherClass if I don't need it, since this is just a class of static utility, such as methods:

 public void method(OtherClass util){ util.staticMethod(); } ... method(new OtherClass()); 

Actually, this does not work, since it will always call the implementation of the method from OtherClass, regardless of the object you are passing (even if you pass null ).

I highly recommend not using reflection just to simplify testing, as it bypasses compile-time checking (the wrong method name will not be detected by the compiler) and prevents the use of many functions of your IDE (code completion, javadoc hovers, refactoring support, displaying call hierarchy, transition to the definition ...)

A general approach is to use polymorphic sending. In Java, this requires that the method is not static, not private. Thus, the rule of thumb is: if it requires ridicule, it should not be static.

How best to get an instance of an object depends on your circumstances; dependency injection (your approach), resource locator pattern and singleton pattern, each of which has its advantages and disadvantages.

+1
source

In your code example:

 public void method(){ OtherClass.staticMethod(); } 

As far as I understand, the method should have some kind of logic above, in addition to the static method call, and this is what you want to test, not the static method.

If so, you can write a mock implementation of OtherClass.staticMethod , which either bypasses the entire logic, or returns the required value, or implements a specific logic. This avoids dependency on OtherClass and gives explicit control over it.

0
source

You can use your first approach by changing your method as follows

 public void method(Class<? extends OtherClass> clazz) throws Exception { Method[] mArray = clazz.getMethods(); for(Method m :mArray) { if(!m.isAccessible()) m.setAccessible(true); if((m.getModifiers() & Modifier.STATIC) != 0) { // Here a method which is static is executed. You can change this condition, to suit your needs m.invoke(null); } } } 

And you can call him by calling

 method(OtherClass.class); 

without passing a new object of this class

0
source

You can use reflection:

 // exceptions management omitted public void method(Class<? extends OtherClass> clazz, String methodName) { // methodName could also be a constant if it won't change clazz.getMethod(methodName).invoke(null); } 

Then

 method(OtherClass.class, "staticMethod"); 
0
source

Here is what I just tried:

 public void testMethod(Class<T> clazz) throws Exception{ Method m = clazz.getMethod("staticMethod",null); m.invoke(null,null); } 

I assumed (as mentioned in your example) that the static method does not accept any arguments.

Please see the documentation for getMethod () and inovke () .

0
source

Nothing wrong with the bit of static code here and there - if it doesn't gain access to the global state:

If the static code is purely procedural

 public void method(){ OtherClass.staticMethod(); } 

You can mock method () if you save a static call as the only operation in your method

If your static method protects any global state, you would be better off using Singleton + Locator

 public class Registry { DoSomethingInterface getOtherClass() { return OtherClass.getSingleton(); } } public void method(Registry reg){ reg.getOtherClass().doSomething(); } 

you can then subclass the registry to provide all varieties of the getOtherClass () locator so that you can create an instance of TestRegistry during testing, taking care of providing a clean global state and other things

If you still need a static class because you cannot change it in any way (for example, a library class), you can wrap it in your interface:

 public class Registry { DoSomethingInterface getOtherClass() { return new DoSomethingInterface(){ public void doSomething() { OtherClass.staticMethod(); } }; } } 
0
source

All Articles