Java 新手入门:Java单元测试利器,Mock详解_java mock-CSDN博客
这个是典型的before when assert三段式,学一下单测思路

这个没有动态代理,所以是直接class(对比下面)
Jmockit使用笔记_增加代码覆盖率_覆盖try catch_使用new MockUp私有方法-CSDN博客
new mock up:
Jmockit使用@MockUp控制被注入Service的方法_mockup使用教程-CSDN博客
默认方法的含义
在 JMockit 中,当一个类的依赖(如 链接的UserService)被注入时,如果没有为该依赖的某个方法设置具体的行为,JMockit 会提供一个默认实现。这个默认实现通常是:
- 对于 返回值类型 的方法:
- 返回值类型是
int或其他基本类型时,返回其默认值(如0、false等)。 - 返回值类型是对象时,返回
null。
- 返回值类型是
- 对于
void方法:- 不执行任何实际逻辑,相当于一个空实现。
由于 userService 是被 JMockit 模拟的,setUserId 方法的默认实现 不会修改 orderInfo 的 userId 属性。因此:
orderInfo.getUserId()始终为null

模拟类里面的方法:
方式一:使用new Expectations()
@Test
public void getOrderInfo1() {new Expectations() {{userService.setUserId((OrderInfo) any);result = new Delegate<OrderInfo>() {void delegate(OrderInfo orderInfo) {orderInfo.setUserId("ZHANGSAN123"); // 模拟方法逻辑}};}};OrderInfo result = testService.getOrderInfo("123");// 验证结果Assert.assertEquals("ZHANGSAN123", result.getUserId());
}
这部分代码是 JMockit 的 Expectations 定义,主要用来模拟依赖对象 userService 的行为。
-
userService.setUserId((OrderInfo) any)
声明当userService的setUserId方法被调用时,不管传入的参数是什么((OrderInfo) any),都会执行后续的行为。 -
result = new Delegate<OrderInfo>()
为被调用的方法定义了一个代理逻辑(即模拟实现)。这里Delegate是 JMockit 提供的功能,用来自定义方法的执行逻辑。 -
代理逻辑:
void delegate(OrderInfo orderInfo)- 传入的
orderInfo对象是调用setUserId方法时的参数。 - 在代理逻辑中,直接对
orderInfo的userId属性赋值为"ZHANGSAN123"。
- 传入的

解读:
-
userService.setUserId((OrderInfo) any)
定义了userService的setUserId方法在接收到任何OrderInfo对象作为参数时,会执行以下逻辑。 -
result = new Delegate<OrderInfo>() { ... }
通过Delegate为方法提供了具体的代理逻辑:- 当
setUserId被调用时,不会执行真实的实现,而是执行代理逻辑,直接将orderInfo.userId设置为"ZHANGSAN123"。
- 当
Expectations 如何影响依赖对象?
示例:
OrderInfo result = testService.getOrderInfo("123");
-
依赖方法调用:
testService.getOrderInfo会调用userService.setUserId(orderInfo)。
-
方法替换:
- 因为用
Expectations模拟了setUserId方法,实际调用的不是UserService的真实方法,而是Expectations中定义的代理逻辑。
- 因为用
-
逻辑执行:
- 在代理逻辑中,将
orderInfo.userId设置为"ZHANGSAN123"。
- 在代理逻辑中,将
-
结果返回:
- 通过修改后的
OrderInfo对象返回给调用方。
- 通过修改后的
基本原理Expectations 是 JMockit 提供的一种基于 声明式 的方式,用于定义某个依赖对象的方法行为。
- 通过在测试代码中定义具体的行为,测试框架根据定义的规则动态返回结果或执行逻辑。
- 对特定实例生效,不影响该类的其他实例。
方式2:使用new mockup()推荐:更easy
new MockUp<UserService>(userService.getClass()) {@Mockpublic void setUserId(OrderInfo orderInfo) {orderInfo.setUserId("zhangsan123");}
};
基本原理MockUp 是 JMockit 提供的一种方式,用于在运行时修改类的方法实现。
- 可以直接为某个类的具体方法编写新的实现,类似于 重写方法。
- 使用
@Mock注解标记需要模拟的方法。
注意:
/*** @author xinruoxiangyang9010* 这里的参数必须是:userService.getClass()* 如果写成UserService.class则@Mock里面的方法不生效*/
new MockUp<UserService>(userService.getClass())
1. UserService.class
- 表示类级别的代理:
当你使用new MockUp<UserService>()或new MockUp<UserService>(UserService.class)时,JMockit 会针对UserService类本身 进行代理。- 它的效果是全局生效,影响所有实例。
- 但是,如果在运行时,你注入的是
userService的一个动态代理对象(比如 Spring 的动态代理机制生成的对象),代理逻辑不会直接生效。
2. userService.getClass()
- 表示对象所属的动态类型:
userService.getClass()返回的是userService实际运行时的类型。- 如果
userService是被 Spring 动态代理(如 CGLIB 或 JDK 动态代理)生成的对象,那么userService.getClass()返回的就是这个动态代理类。 MockUp会针对这个动态代理类生效,从而让@Mock标注的方法在调用时起作用。
- 如果
在实际项目中,特别是使用 Spring 框架时,@Autowired 注入的 userService 很可能是一个动态代理对象,而不是直接的 UserService 实例。
假设 userService 是通过 Spring 注入的动态代理对象:
System.out.println(userService.getClass()); // 输出类似 com.example.UserService$$EnhancerBySpringCGLIB$$12345