mockito 不支持修改私有字段,因其遵循“面向行为的测试”理念,专注模拟方法调用而非操作内部状态;需改私有字段时应使用反射(如 setaccessible + set)或更优的构造注入、setter 等方式。

Mockito 本身不支持直接修改私有属性,它专注于行为模拟(mock method calls),而不是字段操作。若要在单元测试中修改私有字段(比如注入依赖、设置初始状态),需借助 Java 反射机制手动操作,而非 Mockito 提供的功能。
为什么 Mockito 不提供修改私有字段的能力
Mockito 的设计哲学是“面向行为的测试”——关注对象调用什么方法、返回什么结果、是否触发某些交互,而非关心内部字段值。私有字段属于实现细节,Mockito 鼓励通过构造函数、setter 或工厂方式暴露可测性,而非强行反射修改。
用反射修改私有字段的通用做法
Java 反射可通过 Field.setAccessible(true) 绕过访问控制,再用 Field.set() 赋值。适用于需要临时替换私有依赖(如 DAO、Service)或设置特定状态的场景。
- 获取目标字段:通过
Class.getDeclaredField("fieldName") - 关闭访问检查:
field.setAccessible(true) - 设置新值:
field.set(instance, newValue) - 注意:若字段是
final,还需先修改其modifiers字段(需额外反射操作,JDK 12+ 限制更严)
结合 Mockito 使用的典型场景示例
假设有一个类依赖私有字段 private UserService userService,且无 setter 或构造参数:
UserService mockUserSvc = Mockito.mock(UserService.class);
Mockito.when(mockUserSvc.findById(1L)).thenReturn(new User("Alice"));
MyService target = new MyService();
Field field = MyService.class.getDeclaredField("userService");
field.setAccessible(true);
field.set(target, mockUserSvc); // 注入 mock 实例
// 现在可安全调用 target 的方法,其内部会使用 mockUserSvc
也可封装为工具方法(如 Spring 的 ReflectionTestUtils.setField()),避免重复写反射样板代码。
更推荐的替代方案
比起硬编码反射,优先考虑以下更稳定、可读性更强的方式:
- 为私有依赖添加 package-private 或 protected 的 setter 方法(仅测试包可见)
- 通过构造函数注入所有协作对象(最符合测试友好原则)
- 使用依赖注入框架(如 Spring Test)配合
@MockBean自动处理 - 用
Mockito.spy()配合doReturn().when(spy).method()控制部分行为,减少对字段修改的依赖
反射修改字段有效但脆弱——字段名变更、重构为 final、模块封装(JDK 9+)都可能导致测试失败。应作为兜底手段,而非首选。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











