单元测试之Mockito
依赖
引入 Mockito 和 JUnit 依赖:
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-core --> <!-- <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>4.6.1</version> <scope>test</scope> </dependency> --> <!-- 如果需要对静态方法进行打桩,使用 mockito-inline 代替 mockito-core --> <!-- https://mvnrepository.com/artifact/org.mockito/mockito-inline --> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-inline</artifactId> <version>4.6.1</version> <scope>test</scope> </dependency> <!-- 引入 MockitoExtension 类 --> <!-- https://mvnrepository.com/artifact/org.mockito/mockito-junit-jupiter --> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-junit-jupiter</artifactId> <version>4.6.1</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api --> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.9.0-M1</version> <scope>test</scope> </dependency>
IDEA
快捷键:
Ctrl + Shift + T
生成/查找测试类Alt + Insert
->test
生成测试类

查看测试覆盖率:
JUnit
JUnit 注解:
class StudentServiceTest { @BeforeAll public static void beforeAll() { // 所有方法之前执行,只执行一次 } @AfterAll public static void afterAll() { // 所有方法之后执行,只执行一次 } @BeforeEach public void beforeEach() { // 每个方法之前执行 } @AfterEach public void afterEach() { // 每个方法之后执行 } @Test void getById() { // 测试方法 } }
Mockito
Mockito 注解:
@ExtendWith(MockitoExtension.class)
:使 Mockito 注解生效@InjectMocks
:用于标记测试类,它会将 Mock 对象和 Spy 对象注入测试类@Mock
:虚构一个对象,如果没有打桩,该对象的方法会返回类型的默认值@Spy
:虚构一个对象,如果没有打桩,该对象的方法会调用真实的方法
打桩:通过
when()
定义方法的行为
不要将
@InjectMocks
和@Spy
同时使用,会导致不可预测的结果
@ExtendWith(MockitoExtension.class) class StudentServiceTest { @InjectMocks private StudentService studentService; @Mock private StudentDao studentDao; @Spy private Random random; @Test void getById() { // 测试方法 } }
单元测试
单元测试时,我们仅需要对测试类的业务逻辑进行测试,而它的依赖(比如数据库、请求对象或其他中间件)可以通过 mock 来虚构并注入。
@Test void test1() { // 未对 StudentDao 进行打桩,默认返回 null Student student = studentService.getById(1L); assertNull(student); }
@Test public void test2() { // 打桩,返回学生对象 when(studentDao.getById(1L)).thenReturn(new Student(1L, "小明", 18)); Student student = studentService.getById(1L); assertNotNull(student); assertEquals(1L, student.getId()); assertEquals("小明", student.getName()); assertEquals(18, student.getAge()); verify(studentDao).getById(1L); // 验证 studentDao.getById(1L) 被调用 1 次 verify(studentDao, times(1)).getById(1L); // 同上,但可以指定调用次数 }
@Test public void test3() { // 打桩,抛出异常 when(studentDao.getById(1L)).thenThrow(new RuntimeException()); assertThrows(RuntimeException.class, () -> studentService.getById(1L)); }
@Test public void test4() { // 对静态方法进行打桩 try (MockedStatic<StaticUtils> staticUtils = mockStatic(StaticUtils.class)) { staticUtils.when(StaticUtils::name).thenReturn("nothing"); assertEquals("nothing", StaticUtils.name()); } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)