When using Mockito 1.9.x I have been using Whitebox
to set values of fields to "inject" mocks. Se example below:
@Before public void setUp() { eventHandler = new ProcessEventHandler(); securityService = new SecurityServiceMock(); registrationService = mock(RegistrationService.class); Whitebox.setInternalState(eventHandler, "registrationService", registrationService); Whitebox.setInternalState(eventHandler, "securityService", securityService); }
I really like this approach, but now that I tried to upgrade to Mockito
2.2.7
I noticed (or rather, my IDE noticed and told me quite a few times) that Whitebox was no longer to be found in Mockito.
I have found one alternative, that can work as a replacement, and that is org.powermock.reflect.Whitebox
, the problem with that is that I get another dependency (Powermock), just to use Whitebox.
Powermock
also have a class named Whitebox
, but unfortunately it looks as if it can not be used with Mockito 2.2.x
Is there any good alternatives in Mockito that I can use to manually "inject" fields, now that Whitebox
is no longer available?
Solution
I wrote in a comment in response to the post made of @JeffBowman. In short I chose to copy the code of WhiteBox, and use that, since it is used in most of the test cases and the class does not have dependencies to other classes. It was the fastest path to solve this issue.
Note The solution that @bcody suggest is a better alternative, if you are using spring, it ads no extra code for you to maintain. I got that information to late :(
57 Answers
If you are using Spring (the spring-test library specifically), you can simply use ReflectionTestUtils.setField
instead of Whitebox.setInternalState
Note that Whitebox
was always in the org.mockito.internal
package. Beyond the incrementing of the major version number, the internal
designation is a giveaway that the package may be subject to breaking changes.
If you do want to make it a point to set otherwise-inaccessible fields in your test, you can do so in the same way that setInternalState
does, which is just to identify the field in the hierarchy, call setAccessible
on it, and then set it. The full code is here on grepcode. You can also examine a number of other ways to set inaccessible state in tests.
public static void setInternalState(Object target, String field, Object value) { Class<?> c = target.getClass(); try { Field f = getFieldFromHierarchy(c, field); // Checks superclasses. f.setAccessible(true); f.set(target, value); } catch (Exception e) { throw new RuntimeException( "Unable to set internal state on a private field. [...]", e); } }
However, in situations like this, my general advice is to stop fighting the tools: Java's four levels of encapsulation (public, protected, package, private) are not necessarily granular enough to express the degree of protection you're trying to express, and it's often much easier to add a well-documented initialization method or constructor override to override the dependencies as you're trying to do reflectively. If you put your tests in the same Java package as the class it tests, you can often even make the fields or method/constructor package-private, which is also a good reason to set up parallel source folders src
and tests
(etc) that represent two halves of the same Java package.
Though some treat this additional method or constructor as "API pollution", I see it instead as coding to the requirements of one of your class's most important consumers—its own test. If you need a pristine external interface, you can easily define one separately such that you can hide any details you'd like. However, you may find you like the ability to inject any real or mock implementation directly into your now-more-flexible component, at which point you may want to look into dependency injection patterns or frameworks.
6You can use FieldSetter in Mockito2.x
import org.mockito.internal.util.reflection.FieldSetter; FieldSetter.setField(eventHandler,eventHandler.getClass().getDeclaredField("securityService"), securityService);
1The cleanest, neatest and most portable way without reinventing the wheel is to use Apache Commons' FieldUtils
. https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/reflect/FieldUtils.html
The answer to your question would then be
public static void setStaticFieldValue( @NonNull final Class<?> clz, @NonNull final String fieldName, @NonNull final Object value) throws Exception { final Field f = FieldUtils.getField(clz, fieldName, true); FieldUtils.removeFinalModifier(f); f.set(null, value); }
1Here with fest-reflect api you can find an easy to use fluent API for reflection support. This is what I use as an alternative to Mockito's Whiltebox.
The important distinction between plain old Java and plain new Java is getDeclaredField/s
returns private fields.
public static Object getField(Object o, String name) { try { Field f = o.getClass().getDeclaredField(name); f.setAccessible(true); return f.get(o); } catch (Exception ex) { log.info(o.getClass() + " " + name + " " + ex.getMessage(), ex); } return null; } public static void setField(Object o, String name, Object value) { try { Field f = o.getClass().getDeclaredField(name); f.setAccessible(true); f.set(o, value); } catch (Exception ex) { log.info(o.getClass() + " " + name + " " + ex.getMessage(), ex); } }
PowerMock has Whitebox as part of its public API. This is part of powermock-reflect
.
ncG1vNJzZmirpJawrLvVnqmfpJ%2Bse6S7zGiorp2jqbawutJoa2lqaGWGcoSOsJ%2BarF2ZvG61jK6qnmWZo8C1scCdZKieXay1qsDEm6axZZmjeq67wqSgraddZ3pzedOoZKydpGKzqrHLnao%3D