Java单元测试浅析(JUnit+Mockito)
字数 3014 2025-08-11 17:40:32

Java单元测试教学文档(JUnit+Mockito)

1. 单元测试基础概念

1.1 测试阶段划分

  1. 单元测试:针对计算机程序模块进行输出正确性检验工作
  2. 集成测试:在单元测试基础上,整合各个模块组成子系统进行测试
  3. 系统测试:将整个交付所涉及的协作内容都纳入其中考虑,包含计算机硬件、软件、接口等
  4. 验收测试:在交付或发布之前对所做工作进行测试检验

1.2 单元测试特征

  1. 主要功能是证明编写的代码内容与期望输出一致
  2. 最小最低级的测试内容,由程序员自身发起,保证程序基本组件正常
  3. 主张以过程性的方法为测试单位,简单实用高效为目标
  4. 专注于测试一小块代码,保证基础功能
  5. 剥离与外部接口、存储之间的依赖,使单元测试可控
  6. 任何时间任何顺序执行单元测试都需要成功

2. JUnit框架详解

2.1 JUnit简介

  • 官网:https://junit.org/
  • 特点:
    • Java语言特定设计的单元测试框架
    • 标准测试框架
    • 支持多种IDE(Idea、Eclipse)
    • 可通过Maven引入
    • 方便编写测试代码和查看结果

2.2 JUnit重要概念

名称 功能作用
Assert 断言方法集合
TestCase 表示一个测试案例
TestSuite 包含一组TestCase
TestResult 收集测试结果

2.3 JUnit规范

  1. 测试方法必须使用@Test修饰
  2. 测试方法必须使用public void修饰,不能带参数
  3. 测试代码包结构应与被测试代码保持一致
  4. 测试方法必须可以独立测试,方法间不能有依赖
  5. 测试类一般使用Test作为类名后缀
  6. 测试方法一般使用test作为方法名前缀

2.4 断言API

断言方法 描述
assertNull(String message, Object object) 检查对象是否为空
assertNotNull(String message, Object object) 检查对象是否不为空
assertEquals(String message, Object expected, Object actual) 检查对象值是否相等
assertTrue(String message, boolean condition) 检查条件是否为真
assertFalse(String message, boolean condition) 检查条件是否为假
assertSame(String message, Object expected, Object actual) 检查对象引用是否相等
assertNotSame(String message, Object unexpected, Object actual) 检查对象引用是否不等
assertArrayEquals(String message, Object[] expecteds, Object[] actuals) 检查数组值是否相等
assertThat(String reason, T actual, Matcher<? super T> matcher) 检查对象是否满足给定规则

2.5 JUnit常用注解

  1. @Test:定义测试方法
    • @Test(excepted=xx.class):测试方法抛出指定异常时通过
    • @Test(timeout = 毫秒数):测试方法执行时间是否符合预期
  2. @BeforeClass:所有方法执行前执行,static方法,全局只执行一次
  3. @AfterClass:所有方法执行后执行,static方法,全局只执行一次
  4. @Before:每个测试方法运行前执行一次
  5. @After:每个测试方法运行后执行一次
  6. @Ignore:忽略修饰的测试方法
  7. @RunWith:更改测试执行器

3. JUnit实践应用

3.1 Maven依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

3.2 Controller层测试

@RunWith(SpringRunner.class)
@SpringBootTest(classes = MainApplication.class)
public class StudentControllerTest {
    
    @Autowired
    private WebApplicationContext applicationContext;
    
    private MockMvc mockMvc;
    
    @Before
    public void setupMockMvc(){
        mockMvc = MockMvcBuilders.webAppContextSetup(applicationContext).build();
    }
    
    @Test
    public void addStudent() throws Exception{
        String json="{\"name\":\"张三\",\"className\":\"三年级一班\",\"age\":\"20\",\"sex\":\"男\"}";
        mockMvc.perform(MockMvcRequestBuilders.post("/student/save")
                .contentType(MediaType.APPLICATION_JSON_UTF8)
                .accept(MediaType.APPLICATION_JSON_UTF8)
                .content(json.getBytes()))
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andDo(MockMvcResultHandlers.print());
    }
}

3.3 Service层测试

@RunWith(SpringRunner.class)
@SpringBootTest
public class StudentServiceTest {
    
    @Autowired
    private StudentService studentService;
    
    @Test
    public void getOne() throws Exception {
        Student stu = studentService.selectByKey(5);
        Assert.assertThat(stu.getName(), CoreMatchers.is("张三"));
    }
}

3.4 Dao层测试

@RunWith(SpringRunner.class)
@SpringBootTest
public class StudentDaoTest {
    
    @Autowired
    private StudentMapper studentMapper;
    
    @Test
    @Rollback(value = true)
    @Transactional
    public void insertOne() throws Exception {
        Student student = new Student();
        student.setName("李四");
        student.setMajor("计算机学院");
        student.setAge(25);
        student.setSex('男');
        int count = studentMapper.insert(student);
        Assert.assertEquals(1, count);
    }
}

3.5 异常测试

@Test(expected = ArithmeticException.class)
public void computeScoreTest() {
    studentService.computeScore();
}

3.6 测试套件

@RunWith(Suite.class)
@Suite.SuiteClasses({
    StudentServiceTest.class,
    StudentDaoTest.class
})
public class AllTest {}

3.7 测试覆盖率

  1. 统计意义
    • 发现代码中的盲点
    • 提高代码质量
    • 提升代码设计能力
  2. IDEA查看方法
    • 右键Run 'xxx' with Coverage
    • 导出结果:勾选Open generated HTML in browser

3.8 JUnit插件自动生成

  1. 安装插件
  2. 配置插件
  3. 在类上右键generate...生成测试代码

4. Mockito框架详解

4.1 Mockito简介

  • 官网:https://site.mockito.org
  • 特点:
    • 可以模拟类不仅仅是接口
    • 通过注解方式简单易懂
    • 支持顺序验证
    • 具备参数匹配器

4.2 Mockito使用场景

  1. 实际对象很难被构造出来
  2. 实际对象的特定行为很难被触发
  3. 实际对象可能当前还不存在

4.3 Mockito实践案例

@Test
public void orderBookTest() {
    Book expectBook = new Book(1L, "钢铁是怎样炼成的", "书架A01");
    Mockito.when(bookService.orderBook(any(String.class))).thenReturn(expectBook);
    Book book = studentService.orderBook("");
    System.out.println(book);
    Assert.assertTrue("预定书籍不符", expectBook.equals(book));
}

4.4 Mockito常用API

  1. mock:模拟一个需要的对象
  2. when:配合thenXXX使用,定义当执行什么操作后怎样
  3. any:返回特定对象的缺省值
  4. thenReturn:执行特定操作后返回指定结果
  5. spy:创建监控对象
  6. verify:验证特定行为
  7. doReturn:返回结果
  8. doThrow:抛出特定异常
  9. doAnswer:自定义响应
  10. times:操作执行次数
  11. atLeastOnce:操作至少执行一次
  12. atLeast:操作至少执行指定次数
  13. atMost:操作至多执行指定次数
  14. atMostOnce:操作至多执行一次
  15. doNothing:不做任何处理
  16. doCallRealMethod:监控对象返回真实结果

4.5 Mockito使用要点

  1. 打桩(Stub)

    Mockito.when(bookService.orderBook(any(String.class))).thenReturn(expectBook);
    
  2. 参数匹配

    when(mockedList.get(anyInt())).thenReturn(1000);
    
  3. 次数验证

    verify(mockedList, times(3)).get(1);
    verify(mockedList, atLeastOnce()).get(1);
    verify(mockedList, atLeast(3)).get(1);
    
  4. 顺序验证

    when(bookService.orderBook(""))
        .thenReturn(JSON.parseObject(json1, Book.class))
        .thenReturn(JSON.parseObject(json2, Book.class))
        .thenReturn(JSON.parseObject(json3, Book.class));
    
  5. 异常验证

    @Test(expected = RuntimeException.class)
    public void exceptionTest() {
        List mockedList = mock(List.class);
        doThrow(new RuntimeException()).when(mockedList).add(1);
        mockedList.add(1);
    }
    

5. 最佳实践总结

  1. 单元测试原则

    • 保持测试独立性和可重复性
    • 测试代码应与生产代码同等重视
    • 测试应快速执行
    • 测试应覆盖主要业务逻辑
  2. JUnit与Mockito结合

    • 使用JUnit进行基本测试框架
    • 使用Mockito模拟外部依赖
    • 结合Spring Test进行集成测试
  3. 持续改进

    • 定期检查测试覆盖率
    • 重构测试代码保持可维护性
    • 将测试纳入持续集成流程
Java单元测试教学文档(JUnit+Mockito) 1. 单元测试基础概念 1.1 测试阶段划分 单元测试 :针对计算机程序模块进行输出正确性检验工作 集成测试 :在单元测试基础上,整合各个模块组成子系统进行测试 系统测试 :将整个交付所涉及的协作内容都纳入其中考虑,包含计算机硬件、软件、接口等 验收测试 :在交付或发布之前对所做工作进行测试检验 1.2 单元测试特征 主要功能是证明编写的代码内容与期望输出一致 最小最低级的测试内容,由程序员自身发起,保证程序基本组件正常 主张以过程性的方法为测试单位,简单实用高效为目标 专注于测试一小块代码,保证基础功能 剥离与外部接口、存储之间的依赖,使单元测试可控 任何时间任何顺序执行单元测试都需要成功 2. JUnit框架详解 2.1 JUnit简介 官网:https://junit.org/ 特点: Java语言特定设计的单元测试框架 标准测试框架 支持多种IDE(Idea、Eclipse) 可通过Maven引入 方便编写测试代码和查看结果 2.2 JUnit重要概念 | 名称 | 功能作用 | |-----------|--------------------------| | Assert | 断言方法集合 | | TestCase | 表示一个测试案例 | | TestSuite | 包含一组TestCase | | TestResult| 收集测试结果 | 2.3 JUnit规范 测试方法必须使用 @Test 修饰 测试方法必须使用 public void 修饰,不能带参数 测试代码包结构应与被测试代码保持一致 测试方法必须可以独立测试,方法间不能有依赖 测试类一般使用 Test 作为类名后缀 测试方法一般使用 test 作为方法名前缀 2.4 断言API | 断言方法 | 描述 | |-----------------------------------------------|----------------------------------------| | assertNull(String message, Object object) | 检查对象是否为空 | | assertNotNull(String message, Object object) | 检查对象是否不为空 | | assertEquals(String message, Object expected, Object actual) | 检查对象值是否相等 | | assertTrue(String message, boolean condition) | 检查条件是否为真 | | assertFalse(String message, boolean condition) | 检查条件是否为假 | | assertSame(String message, Object expected, Object actual) | 检查对象引用是否相等 | | assertNotSame(String message, Object unexpected, Object actual) | 检查对象引用是否不等 | | assertArrayEquals(String message, Object[] expecteds, Object[] actuals) | 检查数组值是否相等 | | assertThat(String reason, T actual, Matcher<? super T> matcher) | 检查对象是否满足给定规则 | 2.5 JUnit常用注解 @Test :定义测试方法 @Test(excepted=xx.class) :测试方法抛出指定异常时通过 @Test(timeout = 毫秒数) :测试方法执行时间是否符合预期 @BeforeClass :所有方法执行前执行,static方法,全局只执行一次 @AfterClass :所有方法执行后执行,static方法,全局只执行一次 @Before :每个测试方法运行前执行一次 @After :每个测试方法运行后执行一次 @Ignore :忽略修饰的测试方法 @RunWith :更改测试执行器 3. JUnit实践应用 3.1 Maven依赖 3.2 Controller层测试 3.3 Service层测试 3.4 Dao层测试 3.5 异常测试 3.6 测试套件 3.7 测试覆盖率 统计意义 : 发现代码中的盲点 提高代码质量 提升代码设计能力 IDEA查看方法 : 右键Run 'xxx' with Coverage 导出结果:勾选Open generated HTML in browser 3.8 JUnit插件自动生成 安装插件 配置插件 在类上右键generate...生成测试代码 4. Mockito框架详解 4.1 Mockito简介 官网:https://site.mockito.org 特点: 可以模拟类不仅仅是接口 通过注解方式简单易懂 支持顺序验证 具备参数匹配器 4.2 Mockito使用场景 实际对象很难被构造出来 实际对象的特定行为很难被触发 实际对象可能当前还不存在 4.3 Mockito实践案例 4.4 Mockito常用API mock :模拟一个需要的对象 when :配合thenXXX使用,定义当执行什么操作后怎样 any :返回特定对象的缺省值 thenReturn :执行特定操作后返回指定结果 spy :创建监控对象 verify :验证特定行为 doReturn :返回结果 doThrow :抛出特定异常 doAnswer :自定义响应 times :操作执行次数 atLeastOnce :操作至少执行一次 atLeast :操作至少执行指定次数 atMost :操作至多执行指定次数 atMostOnce :操作至多执行一次 doNothing :不做任何处理 doCallRealMethod :监控对象返回真实结果 4.5 Mockito使用要点 打桩(Stub) : 参数匹配 : 次数验证 : 顺序验证 : 异常验证 : 5. 最佳实践总结 单元测试原则 : 保持测试独立性和可重复性 测试代码应与生产代码同等重视 测试应快速执行 测试应覆盖主要业务逻辑 JUnit与Mockito结合 : 使用JUnit进行基本测试框架 使用Mockito模拟外部依赖 结合Spring Test进行集成测试 持续改进 : 定期检查测试覆盖率 重构测试代码保持可维护性 将测试纳入持续集成流程