Mockito无法mock/spy情况下的解决方法
Mockito不支持mock/spy如下的类型:
- final classes
- anonymous classes
- primitive types
如果你mock这些类型,会抛出如下错误信息:
org.mockito.exceptions.base.MockitoException: Cannot mock/spy class java.lang.String Mockito cannot mock/spy following: - final classes - anonymous classes - primitive types
而如果你有确实有此需求,可以通过如下方法解决。先定义一个工具类,里面包含如下方法:
public static void injectField(final Object injectable, final String fieldname, final Object value) {
try {
final java.lang.reflect.Field field = injectable.getClass().getDeclaredField(fieldname);
final boolean origionalValue = field.isAccessible();
field.setAccessible(true);
field.set(injectable, value);
field.setAccessible(origionalValue);
} catch (final NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
比如你有如下类需要测试:
public class Greeting {
@Inject
private String greeting;
@Override
public String toString() {
return this.greeting;
}
}
那么,你的测试类大概如下:
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
public class GreetingTest {
@Test
public void testToString() throws Exception {
Greeting greeting = new Greeting();
injectField(greeting, "greeting", "Hello, world");
assertThat(greeting.toString(), is("Hello, world"));
}
}
以上参考:https://dzone.com/articles/field-injection-when-mocking-frameworks-fail
当然,如果你使用Spring Test,你可以使用org.springframework.test.util.ReflectionTestUtils。 类似
ReflectionTestUtils.setField(testObject, "person", mockedPerson);
。
或者,如果你使用Mockito 1.*,可以使用
import org.mockito.internal.util.reflection.FieldSetter;
new FieldSetter(obj, obj.getClass().getDeclaredField("p")).set(new P());
//or
org.mockito.internal.util.reflection.Whitebox#setInternalState(Object target, String field, Object value)
针对Mockito 2.*,可以使用:
org.mockito.internal.util.reflection.FieldSetter.setField(Object target, Field field, Object value)