使用 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 中修改属性名时,用于反射时的属性字符串不会被自动修改也无妨,本来就是测试用例,跑一下测试用例就能发现问题了。

 


2020-06-03

使用 powermock-reflect 的 Whitebox

既然 Mockito 2 把 Whitebox 移除了,再创建一个 Whitebox 还不如使用另一个第三方测试好的 Whitebox 实现,那就是 powermock-reflect 的 Whitebox 类。我们不完全使用 PowerMockRunner, 只用到  powermock-reflect 模块,引入

它提供了更丰富的 API, 还不用自己写,避免犯错

本文链接 https://yanbin.blog/mockito-modify-private-field/, 来自 隔叶黄莺 Yanbin Blog

[版权声明] Creative Commons License 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。

Subscribe
Notify of
guest

3 Comments
Inline Feedbacks
View all comments
maomao
maomao
4 years ago

赞一个,找了好久

Adam
Adam
4 years ago

无意中发现这篇文章, 解决了我一直以来比较头疼的一个问题. 多谢.