What do I use instead of Whitebox in Mockito 2.2 to set fields?

六眼飞鱼酱① 提交于 2019-12-01 02:22:28
Jeff Bowman

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.

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

foo

The 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);
}

You can use FieldSetter in Mockito2.x

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

Here 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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!