Junit
使用方式
Junit4
- 引入依赖包
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
- 编写测试类
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class CalculatorTest {
@Test
public void testAdd() {
Calculator calculator = new Calculator();
int result = calculator.add(2, 3);
assertEquals(5, result);
}
}
- 常用注解
@Test: 标记一个方法为测试方法。
@Before: 每个测试方法之前运行。
@After: 每个测试方法之后运行。
@BeforeClass: 在所有测试方法之前运行,仅运行一次。
@AfterClass: 在所有测试方法之后运行,仅运行一次。
Junit5
- 引入依赖包
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
<!-- 或者只引入下面的就可以了-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
- 编写测试类
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class CalculatorTest {
@Test
public void testAdd() {
Calculator calculator = new Calculator();
int result = calculator.add(2, 3);
assertEquals(5, result);
}
}
- 常用注解
@Test: 标记一个方法为测试方法。
@BeforeEach: 每个测试方法之前运行。
@AfterEach: 每个测试方法之后运行。
@BeforeAll: 在所有测试方法之前运行,仅运行一次。
@AfterAll: 在所有测试方法之后运行,仅运行一次。
Junit 和Junit5 区别
架构和模块化
-
JUnit 4:
- 单一 jar 文件。
- 所有功能都集中在一个库中。
-
JUnit 5:
- 模块化设计,由三个子项目组成:
- JUnit Platform: 提供运行测试的基础设施。
- JUnit Jupiter: 提供新的测试编写和扩展模型。
- JUnit Vintage: 提供运行 JUnit 3 和 JUnit 4 测试的支持。
- 模块化设计,由三个子项目组成:
注解
-
JUnit 4:
-
@Test
: 标记测试方法。 -
@Before
: 每个测试方法之前运行。 -
@After
: 每个测试方法之后运行。 -
@BeforeClass
: 在所有测试方法之前运行,仅运行一次。 -
@AfterClass
: 在所有测试方法之后运行,仅运行一次。 -
@Ignore
: 忽略测试方法。
-
-
JUnit 5:
-
@Test
: 标记测试方法。 -
@BeforeEach
: 每个测试方法之前运行。 -
@AfterEach
: 每个测试方法之后运行。 -
@BeforeAll
: 在所有测试方法之前运行,仅运行一次。 -
@AfterAll
: 在所有测试方法之后运行,仅运行一次。 -
@Disabled
: 忽略测试方法或测试类。 -
@Nested
: 用于表示嵌套的测试类。 -
@Tag
: 用于标记测试以便进行分组和过滤。 -
@DisplayName
: 为测试方法提供自定义名称。
-
断言
-
JUnit 4:
- 使用
org.junit.Assert
类中的静态方法,例如assertEquals
、assertTrue
等。
- 使用
-
JUnit 5:
- 使用
org.junit.jupiter.api.Assertions
类中的静态方法,增加了一些新的断言方法和功能,例如assertAll
、assertThrows
等。
- 使用
条件测试执行
-
JUnit 4:
- 通过第三方库(如 Assume)实现条件测试执行。
-
JUnit 5:
- 内置条件执行注解,如
@EnabledOnOs
、@DisabledOnOs
、@EnabledOnJre
、@DisabledOnJre
、@EnabledIf
、@DisabledIf
等。
- 内置条件执行注解,如
动态测试
-
JUnit 4:
- 不支持动态测试。
-
JUnit 5:
- 使用
@TestFactory
和DynamicTest
提供对动态测试的支持,可以在运行时生成测试用例。
- 使用
参数化测试
-
JUnit 4:
- 使用
@RunWith(Parameterized.class)
和其他注解来实现参数化测试。
- 使用
-
JUnit 5:
- 使用
@ParameterizedTest
注解,并结合多个源注解(如@ValueSource
、@MethodSource
、@CsvSource
等)来实现更灵活和强大的参数化测试。
- 使用
扩展模型
-
JUnit 4:
- 通过
@RunWith
和TestRule
扩展功能。
- 通过
-
JUnit 5:
- 提供了一个强大的扩展模型,通过实现
Extension
接口,可以更灵活地创建和使用扩展。
- 提供了一个强大的扩展模型,通过实现
向后兼容性
-
JUnit 4:
- 没有向后兼容性问题,因为是单一框架。
-
JUnit 5:
- 提供了 JUnit Vintage 引擎,允许在 JUnit 5 平台上运行 JUnit 3 和 JUnit 4 的测试,以便逐步迁移到 JUnit 5。
依赖包说明
JUnit Jupiter API:提供了编写测试所需的所有注解和类,如 @Test
, @BeforeEach
, @AfterEach
等。
JUnit Jupiter Engine:用于执行基于 JUnit Jupiter 的测试。这个引擎在添加 junit-jupiter
依赖时自动包含。
所以引入下面的就可以
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
Spring Test
spring-test
是 Spring Framework 提供的一个模块,旨在简化 Spring 应用程序的测试。它为测试 Spring 应用程序中的组件和集成提供了支持,特别是在使用 Spring 的上下文和依赖注入时。spring-test
模块提供了一些重要的功能和工具,帮助开发人员更容易地编写和执行测试。
- 引入依赖包
<dependencies>
<!-- Spring Context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.22</version>
</dependency>
<!-- Spring Test -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.22</version>
<scope>test</scope>
</dependency>
<!-- JUnit Jupiter -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.9.3</version>
<scope>test</scope>
</dependency>
<!-- Mockito -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.11.0</version>
<scope>test</scope>
</dependency>
</dependencies>
- 编写测试代码
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import static org.junit.jupiter.api.Assertions.*;
// 扩展JUnit 5以支持Spring
@ExtendWith(SpringExtension.class)
// 使用mock对象
@ExtendWith(MockitoExtension.class)
// 指定Spring配置类或XML配置文件
@ContextConfiguration(classes = AppConfig.class)
public class MyServiceTest {
@Autowired
private MyService myService;
@Test
public void testService() {
String result = myService.performAction();
assertEquals("expectedResult", result);
}
}
或者
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import static org.junit.jupiter.api.Assertions.*;
@SpringJUnitConfig(AppConfig.class)
public class MyServiceTest {
@Autowired
private MyService myService;
@Test
public void testService() {
String result = myService.performAction();
assertEquals("expectedResult", result);
}
}
或者 Test SpringMVC
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = MyControllerTest.WebConfig.class)
public class MyControllerTest {
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
@Configuration
@EnableWebMvc
static class WebConfig {
@Bean
public MyController myController() {
return new MyController();
}
}
@BeforeEach
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
@Test
public void testGetEndpoint() throws Exception {
mockMvc.perform(get("/my-endpoint"))
.andExpect(status().isOk())
.andExpect(content().string("expectedResponse"));
}
}
@SpringJUnitConfig
和 @ExtendWith(SpringExtension.class)
都是用于在 JUnit 5 中整合 Spring Test 框架的注解。它们有着相似的作用,但使用方式略有不同。
@ExtendWith(SpringExtension.class)
@ExtendWith(SpringExtension.class)
是 JUnit 5 提供的一种扩展机制,用于扩展测试的行为。SpringExtension
是 Spring Test 提供的一个扩展,用于在 JUnit 5 测试中启用 Spring Test 上下文。
使用 @ExtendWith(SpringExtension.class)
时,您通常需要另外添加 @ContextConfiguration
或其他 Spring 的配置注解来指定配置类或配置文件。
@SpringJUnitConfig
@SpringJUnitConfig
是一个复合注解,它结合了 @ExtendWith(SpringExtension.class)
和 @ContextConfiguration
,使得配置更加简洁。这意味着使用 @SpringJUnitConfig
不需要额外添加 @ContextConfiguration
注解,因为它已经包含了这一功能。
如果您只是进行基本的 Spring 测试,不需要其他额外的扩展,使用 @SpringJUnitConfig
会更加简洁和方便。
如果您的测试类中需要使用多个 JUnit 5 扩展(如 Mockito 等),使用 @ExtendWith(SpringExtension.class)
会更加灵活。
@ContextConfiguration
注解用于在 Spring 测试中指定 Spring 应用上下文的配置。通过这个注解,您可以告诉 Spring 在测试运行时加载哪些配置类或配置文件,从而初始化 Spring 应用上下文。主要用途
- 指定配置类:通过
classes
属性,您可以指定一个或多个 Java 配置类。- 指定配置文件:通过
locations
属性,您可以指定一个或多个 XML 配置文件的位置。- 继承上下文配置:在继承测试类时,可以通过
@ContextConfiguration
实现配置的继承和覆盖。属性
classes
:用于指定一个或多个配置类。locations
:用于指定一个或多个 XML 配置文件的路径。initializers
:用于指定一个或多个ApplicationContextInitializer
实现类,可以在应用上下文刷新之前对其进行初始化。inheritLocations
:指定是否从超类继承@ContextConfiguration
的locations
属性,默认为true
。inheritInitializers
:指定是否从超类继承@ContextConfiguration
的initializers
属性,默认为true
。import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; // 基类测试 @ExtendWith(SpringExtension.class) @ContextConfiguration(classes = BaseConfig.class) public class BaseTest { @Autowired protected MyBaseService myBaseService; } // 子类测试,继承上下文配置 @ContextConfiguration(classes = {BaseConfig.class, ChildConfig.class}, inheritLocations = true) public class ChildTest extends BaseTest { @Autowired private MyChildService myChildService; @Test public void testChildService() { assertNotNull(myBaseService); assertNotNull(myChildService); } }
Spring-boot Test
- 引入依赖
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>3.3.0</version>
<scope>test</scope>
</dependency>
这个依赖项会自动引入必要的库来支持 Spring Boot 测试,包括 JUnit 5
- 编写测试类
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.assertj.core.api.Assertions.assertThat;
// @RunWith(SpringRunner.class)是Junit4提供的注解,将Spring和Junit链接了起来。
//假如使用Junit5,不再需要使用@RunWith注解,
//@SpringBootTest和其它@*Test默认已经包含了该注解。
@SpringBootTest
public class MyServiceIntegrationTest {
@Autowired
private MyService myService;
@Test
public void testPerformAction() {
String result = myService.performAction();
assertThat(result).isEqualTo("expectedResult");
}
}
或者,mvcTest
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.mockito.BDDMockito.given;
@WebMvcTest(MyController.class)
public class MyControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private MyService myService;
@Test
public void testGetEndpoint() throws Exception {
given(myService.performAction()).willReturn("expectedResult");
mockMvc.perform(get("/my-endpoint"))
.andExpect(status().isOk())
.andExpect(content().string("expectedResult"));
}
}
或者jpa test
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import static org.assertj.core.api.Assertions.assertThat;
@DataJpaTest
public class MyRepositoryTest {
@Autowired
private MyRepository myRepository;
@Test
public void testFindById() {
MyEntity entity = new MyEntity();
entity.setName("TestName");
myRepository.save(entity);
MyEntity found = myRepository.findById(entity.getId()).orElse(null);
assertThat(found).isNotNull();
assertThat(found.getName()).isEqualTo("TestName");
}
}
@SpringBootTest
:用于加载整个 Spring 应用上下文进行集成测试。适用于需要测试多个组件协作的场景。
@WebMvcTest
:用于加载 Web 层组件(如控制器)进行测试,不加载整个应用上下文。适用于测试控制器及其相关的过滤器、拦截器等。
@DataJpaTest
:用于测试 JPA 持久层组件。它会自动配置嵌入式数据库(如 H2),并对持久层进行测试。
使用@SpringBootTest时并没有像@ContextConfiguration一样显示指定locations或classes属性,原因在于@SpringBootTest注解会自动检索程序的配置文件,检索顺序是从当前包开始,逐级向上查找被@SpringBootApplication或@SpringBootConfiguration注解的类。