使用 Mockito 修改私有属性

修改私有属性来 Mock 可能不是一种很好的测试方式, 因为属性名是动态的,但有时不得已而为了,例如下面的代码:

public class UserService {
    private ExternalApi external = ExternalApi.default();
    private UserDao userDao;

    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }

    public User findUserById(int id) {
        return userDao.findById(external.convertId(id));
}

测试时欲隔离对 ExternalApi 的外部依赖, 当然可以把它也作为构造函数的一个参数,这样创建 UserService 实例时就可以 Mock external 属性。不过 external 经常是不变的,所以作为方法参数的必要性也不大。这就希望能在构造出 UserService 之后对 external 私有属性进行 Mock 处理。

在 Mockito 1.x 和 2.x 下要使用不同的方式,分别使用到 Whitebox 和 FieldSetter 类,它们都来自于  mockito.internal.util.reflection 包,可见 Mockito 打心底不推荐直接使用它们,但谁叫它们是 public 的呢。还有一种方式是使用 PowerMock + Mockito, 这是后话。

Mockito 1.x 修改私有属性

Mockito 2.x 修改私有属性

Mockito 2.x 下移除了 Whitebox, 但可以用 mockito.internal.util.reflection.FieldSetter, 它仅有的方法声明是

public static void setField(Object target, Field field, Object value)

这需要我们用反射的方式找到 Field, 还得处理下异常

如此这般,在 Mockito 2.x 下使用 FieldSetter 倒不如自己写一个 Whitebox 类只提供一个方法来修改私有属性,还无需在测试方法中自己处理异常.

所以 Mockito 2.x 可创建如下的 Whitebox 类来修改私有属性

其实私有属性可能经常变,在 IDE 中修改属性名时,用于反射时的属性字符串不会被自动修改也无妨,本来就是测试用例,跑一下测试用例就能发现问题了。

类别: Java/JEE. 标签: . 阅读(1,049). 订阅评论. TrackBack.

Leave a Reply

Be the First to Comment!

avatar