Mock技巧
1. @Mock 注解
- 作用:
@Mock注解用于创建一个模拟对象(Mock 对象)。模拟对象是一个完全虚拟的对象,它不会执行真实对象的任何方法逻辑,而是根据测试的需要返回预设的值或者执行预设的行为。 - 使用场景:当你想要隔离被测试对象与外部依赖,控制外部依赖的行为时,可以使用
@Mock注解。 - 示例代码
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.mockito.Mockito.when;
// 使用 MockitoExtension 扩展来启用 Mockito 注解
@ExtendWith(MockitoExtension.class)
public class MockExample {
// 创建一个 Mock 对象
@Mock
private MyService myService;
@Test
public void testMock() {
// 预设 Mock 对象的方法行为
when(myService.doSomething()).thenReturn("Mocked result");
// 调用 Mock 对象的方法
String result = myService.doSomething();
// 验证结果
System.out.println(result); // 输出: Mocked result
}
}
class MyService {
public String doSomething() {
return "Real result";
}
}
在上述代码中,myService 是一个 Mock 对象,当调用 doSomething() 方法时,它会返回预设的 "Mocked result",而不是真实的 "Real result"。
2. @Spy 注解
- 作用:
@Spy注解用于创建一个真实对象的包装器(Spy 对象)。Spy 对象会调用真实对象的方法,除非你明确地对某些方法进行了 stub(预设)。 - 使用场景:当你想要测试一个对象的大部分真实行为,但又需要控制某些方法的返回值时,可以使用
@Spy注解。 - 示例代码
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.ArrayList;
import java.util.List;
import static org.mockito.Mockito.doReturn;
// 使用 MockitoExtension 扩展来启用 Mockito 注解
@ExtendWith(MockitoExtension.class)
public class SpyExample {
// 创建一个 Spy 对象
@Spy
private List<String> spyList = new ArrayList<>();
@Test
public void testSpy() {
// 预设 Spy 对象的方法行为
doReturn("Mocked element").when(spyList).get(0);
// 调用 Spy 对象的方法
spyList.add("Real element");
String result = spyList.get(0);
// 验证结果
System.out.println(result); // 输出: Mocked element
}
}
在上述代码中,spyList 是一个 Spy 对象,当调用 add() 方法时,它会执行真实的添加操作;而当调用 get(0) 方法时,它会返回预设的 "Mocked element"。
3. @InjectMocks 注解
- 作用:
@InjectMocks注解用于创建一个真实对象,并将使用@Mock或@Spy注解创建的模拟对象或 Spy 对象注入到该真实对象的依赖中。 - 使用场景:当你想要测试一个对象的真实行为,同时又需要隔离其外部依赖时,可以使用
@InjectMocks注解。 - 示例代码
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.mockito.Mockito.when;
// 使用 MockitoExtension 扩展来启用 Mockito 注解
@ExtendWith(MockitoExtension.class)
public class InjectMocksExample {
// 创建一个 Mock 对象
@Mock
private MyService myService;
// 创建一个真实对象,并注入 Mock 对象
@InjectMocks
private MyClass myClass;
@Test
public void testInjectMocks() {
// 预设 Mock 对象的方法行为
when(myService.doSomething()).thenReturn("Mocked result");
// 调用真实对象的方法
String result = myClass.callService();
// 验证结果
System.out.println(result); // 输出: Mocked result
}
}
class MyClass {
private MyService myService;
public MyClass(MyService myService) {
this.myService = myService;
}
public String callService() {
return myService.doSomething();
}
}
class MyService {
public String doSomething() {
return "Real result";
}
}
在上述代码中,myClass 是一个真实对象,myService 是一个 Mock 对象,通过 @InjectMocks 注解将 myService 注入到 myClass 中。当调用 myClass.callService() 方法时,会调用 myService 的 doSomething() 方法,返回预设的 "Mocked result"。
总结
@Mock:创建一个完全虚拟的对象,不执行真实方法逻辑。@Spy:创建一个真实对象的包装器,默认执行真实方法逻辑,可对部分方法进行 stub。@InjectMocks:创建一个真实对象,并将 Mock 对象或 Spy 对象注入到该真实对象的依赖中
技巧一:当使用jpa或者mybatis自动注入mapper时
先mock一个mapper,
由于injectMock的是userServiceImpl对象,而使用的mapper是从他的父类ServiceImpl里面拿的,所以mapper不能注入到父属性【由于getBaseMapper方法返回的baseMapper是父类】;所以可以在userServiceImpl调用到getMapper时,打桩到userServiceImpl里面
Open: Pasted image 20250219004700.png
getByID实际是调用的Iservice.getByID()=>mapper又是走的父类ServiceImpl的
Open: Pasted image 20250219004812.png
父类:ServiceImpl
Open: Pasted image 20250219005522.png
Open: Pasted image 20250219004853.png



