一、JUnit 简介
JUnit 是一款优秀的开源 Java 单元测试框架,也是目前使用率最高最流行的测试框架。它主要用于白盒测试和回归测试:
- 白盒测试:把测试对象看作一个打开的盒子,程序内部的逻辑结构和其他信息对测试人员是公开的
- 回归测试:软件或环境修复或更正后的再测试
- 单元测试:最小粒度的测试,以测试某个功能或代码块,一般由程序员来做
Spring Boot 默认已经集成了 JUnit 框架支持,开发工具如 Eclipse 和 IDEA 对 JUnit 都有很好的支持。
二、环境准备
2.1 依赖配置
对于 Spring Boot 项目,默认的 spring-boot-starter-test
依赖已经包含了 JUnit 支持:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
这个依赖包中已经包含了 JUnit 5(JUnit Jupiter)、Mockito 和 AssertJ 等测试工具。
三、JUnit 4 与 JUnit 5
3.1 JUnit 4 基础使用
Spring Boot 2.x 早期版本默认使用 JUnit 4,典型的测试类结构如下:
@RunWith(SpringRunner.class)
@SpringBootTest
public class SimpleTest {
@Test
public void doTest() {
int num = new Integer(1);
Assert.assertEquals(num, 1);
}
}
常用注解:
@RunWith(SpringRunner.class)
:标识为 JUnit 的运行环境@SpringBootTest
:获取启动类、加载配置,确定装载 Spring Boot@Test
:声明需要测试的方法@BeforeClass
:针对所有测试,只执行一次,且必须为 static void@AfterClass
:针对所有测试,只执行一次,且必须为 static void@Before
:每个测试方法前都会执行的方法@After
:每个测试方法后都会执行的方法@Ignore
:忽略方法
断言方法:
Assert.assertEquals
:对比两个值相等Assert.assertNotEquals
:对比两个值不相等Assert.assertSame
:对比两个对象的引用相等Assert.assertArrayEquals
:对比两个数组相等Assert.assertTrue
:验证返回是否为真Assert.assertFalse
:验证返回是否为假Assert.assertNull
:验证 nullAssert.assertNotNull
:验证非 null
超时测试:
@Test(timeout = 1000) // 时间单位为毫秒
3.2 JUnit 5 基础使用
JUnit 5 是 JUnit 测试框架的最新版本,由三个主要模块组成:
- JUnit Platform:提供了测试执行的基础设施
- JUnit Jupiter:提供了新的编程模型和扩展模型
- JUnit Vintage:支持运行 JUnit 3 和 JUnit 4 的测试用例
JUnit 5 引入了许多新特性,例如嵌套测试、参数化测试、动态测试等。
典型测试类结构:
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.assertEquals;
@SpringBootTest
public class MyServiceTest {
@Test
public void testSomething() {
// 测试逻辑
assertEquals(2, 1 + 1);
}
}
常用注解:
@Test
:声明需要测试的方法@BeforeEach
:每个测试方法前都会执行的方法(相当于 JUnit 4 的 @Before)@AfterEach
:每个测试方法后都会执行的方法(相当于 JUnit 4 的 @After)@BeforeAll
:针对所有测试,只执行一次,且必须为 static void(相当于 JUnit 4 的 @BeforeClass)@AfterAll
:针对所有测试,只执行一次,且必须为 static void(相当于 JUnit 4 的 @AfterClass)@Disabled
:忽略方法(相当于 JUnit 4 的 @Ignore)
断言方法:
JUnit 5 提供了丰富的断言方法,例如 assertEquals
、assertTrue
等。此外,还可以使用 AssertJ 库提供更流畅的断言语法。
四、Spring Boot 集成 JUnit 5 实践
4.1 测试类基本结构
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.assertEquals;
@SpringBootTest
public class UserServiceTest {
@Test
public void testGetUserById() {
// 假设这里有一个 UserService 实例
// User user = userService.getUserById(1L);
// assertEquals("John Doe", user.getName());
assertEquals(2, 1 + 1); // 示例断言
}
}
4.2 使用 Mockito 进行模拟测试
在单元测试中,我们通常需要模拟外部依赖。Mockito 是一个流行的模拟框架,可以与 JUnit 5 无缝集成。
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.boot.test.context.SpringBootTest;
import static org.mockito.Mockito.when;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.Optional;
@SpringBootTest
public class OrderServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private OrderService orderService;
@Test
public void testCreateOrder() {
User user = new User(1L, "John Doe");
when(userRepository.findById(1L)).thenReturn(Optional.of(user));
Order order = orderService.createOrder(1L, "Laptop");
assertEquals("John Doe", order.getUser().getName());
}
}
4.3 使用 AssertJ 进行流畅断言
AssertJ 提供了更流畅的断言语法:
import static org.assertj.core.api.Assertions.assertThat;
@Test
public void testAssertJ() {
String result = myService.processData();
assertThat(result).isEqualTo("Expected Result");
assertThat(result).contains("Expected");
assertThat(result).startsWith("E");
assertThat(result).isNotEmpty();
}
五、测试类型
5.1 单元测试
单元测试是最小粒度的测试,测试单个类或方法。通常使用 Mockito 来模拟依赖项。
5.2 集成测试
集成测试用于测试多个组件如何协同工作。使用 @SpringBootTest
注解加载完整的 Spring 应用上下文。
@SpringBootTest
public class IntegrationTest {
@Autowired
private MyService myService;
@Test
public void testIntegration() {
// 测试多个组件的集成
}
}
5.3 切片测试
切片测试是介于单元测试和集成测试之间的一种测试,只加载 Spring 应用上下文的一部分。
@WebMvcTest(MyController.class)
public class MyControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void testController() throws Exception {
mockMvc.perform(get("/api/test"))
.andExpect(status().isOk());
}
}
六、测试最佳实践
- 测试命名:使用描述性的测试方法名称,如
shouldReturnXWhenYGivenZ
- 单一职责:每个测试方法应该只测试一个功能点
- AAA 模式:遵循 Arrange-Act-Assert 模式组织测试代码
- 避免过度依赖:尽量使用模拟对象隔离被测代码
- 测试覆盖率:追求有意义的测试覆盖率,而不仅仅是高数字
- 持续集成:将测试作为持续集成流程的一部分
七、总结
Spring Boot 与 JUnit 的集成提供了强大的测试能力,无论是简单的单元测试还是复杂的集成测试都能很好地支持。JUnit 5 作为最新版本,提供了更多现代化特性,使测试更加灵活和强大。通过合理使用 Mockito、AssertJ 等工具,可以编写出高效、可维护的测试代码,从而提高软件质量和开发效率。