What do I use instead of Whitebox in Mockito 2.2 for setting fields?

When using Mockito 1.9.x, I used Whitebox to set the field values ​​for the "injection" mocks. 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, when I tried to upgrade to Mockito 2.2.7 , I noticed (more precisely, my IDE noticed and told me several times) that Whitebox was no longer found in Mockito.

I found one alternative that can work as a replacement, and this is org.powermock.reflect.Whitebox , the problem is that I get another dependency (Powermock) just to use Whitebox. / p>

Powermock also have a class called Whitebox , but unfortunately it looks like it cannot be used with Mockito 2.2.x

Are there any good alternatives in Mockito that I can use for manual input now that Whitebox no longer available?


Decision

I wrote in a comment in response to a post made from @JeffBowman. In short, I decided to copy the WhiteBox code and use it, since it is used in most test cases, and the class has no dependencies on other classes. This was the fastest way to solve this problem.

Note The solution suggested by @bcody is a better alternative if you use spring, it does not contain additional code for your service. I got this information until late :(

+16
source share
5 answers

Note that Whitebox has always been in the org.mockito.internal package. In addition to increasing the main version number, the designation internal is a fake that the package may be subject to change.

If you want to make the otherwise inaccessible field set in your test, you can do it the same way as setInternalState does, which is only 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 learn a few 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 such situations, my general advice is to stop fighting with tools: Java's four levels of encapsulation (public, protected, package, private) are not necessarily granular enough to express the degree of protection you are trying to express, and it is often much easier to add a well-documented one initialize method or override constructor to redefine dependencies as you try to do it reflexively. If you put your tests in the same Java package as the class that it tests, you can often even make the fields or method / constructor a private package, which is also a good reason to set the src and tests parallel source folders (and so on. .d.) that represent the two halves of the same Java package.

Although some see this add-on method or constructor as an β€œAPI pollution,” I instead see it as coding to the requirements of one of your most important consumers of your class β€” your own test. If you need a clean external interface, you can easily define it separately so that you can hide any details that you want. However, you may find that you like to embed any real or mock implementation directly into your now more flexible component, after which you may want to take a look at dependency injection patterns or frameworks.

+6
source

If you use Spring (especially for the spring -test library), you can simply use ReflectionTestUtils.setField instead of Whitebox.setInternalState

+32
source

The cleanest, most sophisticated, and most portable way without reinventing the wheel is to use FieldUtils Apache Commons. https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/reflect/FieldUtils.html

The answer to your question will 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); } 
+4
source

You can use FieldSetter in Mockito2.x

  import org.mockito.internal.util.reflection.FieldSetter; FieldSetter.setField(eventHandler,eventHandler.getClass().getDeclaredField("securityService"), securityService); 
+1
source

Here with the Fest- Reflective API you can find an easy-to-use API to support reflection. This is what I use as an alternative to the Mockito Whiltebox.

0
source

Source: https://habr.com/ru/post/1011754/


All Articles