SpringBootTest单元测试组件
一、SpringbootTest 使用Junit4开发
1、添加依赖
<dependency>
<groupId></groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
2、单元测试类
- @RunWith()
- @SpringBootTest(classes = {})
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootApplicationTests {
@Autowired
private UserService userService;
@Test
public void testAddUser() {
User user = new User();
user.setName("john");
user.setAddress("earth");
userService.add(user);
}
}
3、JUnit4相关注解
-
@BeforeClass:针对所有测试,只执行一次,且必须为static void
-
@Before:初始化方法,执行当前测试类的每个测试方法前执行。
-
@Test:测试方法,在这里可以测试期望异常和超时时间
- timeout = 2000 测试超时
- expected= 测试抛出的异常
-
@After:释放资源,执行当前测试类的每个测试方法后执行
-
@AfterClass:针对所有测试,只执行一次,且必须为static void
-
@Ignore:忽略的测试方法(只在测试类的时候生效,单独执行该测试方法无效)
4、Assert断言相关API
二、SpringbootTest 使用Junit5开发
1、添加依赖
移除掉Junit4的依赖
<dependency>
<groupId></groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.3.2-RELEASE</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId></groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
2、单元测试类
- @ExtendWith()指定测试的引擎类
- @TestMethodOrder()指定测试的顺序
- @SpringBootTest 指定测试的启动类
- args = “–=one” 指定参数
- classes 指定启动类,可以是多个
- value 指定配置属性
- properties 指定配置属性,和value相同
- webEnvironment 指定web环境,
- MOCK 此值为默认值,该类型提供一个mock环境,此时内嵌的服务(servlet容器)并没有真正启动,也不会监听web端口
- RANDOM_PORT 启动一个真实的web服务,监听一个随机端口
- DEFINED_PORT 启动一个真实的web服务,监听一个定义好的端口(从配置中读取)。
- NONE 启动一个非web的ApplicationContext,既不提供mock环境,也不提供真是的web服务
- @Test 指定测试方法
@Slf4j
@ExtendWith(SpringExtension.class)
@TestMethodOrder(MethodOrderer.Alphanumeric.class)
@SpringBootTest(classes = {VipThinkICodeCourseApplication.class})
public class LearnerCourseServiceTest {
@Autowired
private LearnerCourseService learnerCourseService;
@Test
public void getLearnerCourse() {
try {
List<CouseSchedulVo> couseSchedulers = learnerCourseService.getCouseSchedulers(219772514);
System.out.println(JSONUtil.toJsonPrettyStr(couseSchedulers));
} catch (Exception e) {
log.error("单元测试出现异常!", e);
Assertions.assertTrue(true);
}
}
}
3、Junit5相关注解
(1)执行顺序
- @BeforeEach:在每个单元测试方法执行前都执行一遍
- @BeforeAll:在每个单元测试方法执行前执行一遍(只执行一次)
- @AfterAll 表示在所有单元测试之后执行
- @AfterEach 表示在每个单元测试之后执
(2)其他特性
- @DisplayName(“商品入库测试”):用于指定单元测试的名称
- @Disabled:当前单元测试置为无效,即单元测试时跳过该测试
- @RepeatedTest(n):重复性测试,即执行n次
- @ParameterizedTest:参数化测试,
- @ValueSource(ints = {1, 2, 3}):参数化测试提供数据
- @Timeout(value = 3,unit = )
4、Assertions断言
//嵌套单元测试
@SpringBootTest
@AutoConfigureMockMvc
@DisplayName("Junit5单元测试")
public class MockTest {
//....
@Nested
@DisplayName("内嵌订单测试")
class OrderTestClas {
@Test
@DisplayName("取消订单")
void cancelOrder() {
int status = -1;
System.out.println("取消订单成功,订单状态为:"+status);
}
}
}
//参数化测试
@ParameterizedTest
@ValueSource(ints = {1, 2, 3})
@DisplayName("参数化测试")
void paramTest(int a) {
assertTrue(a > 0 && a < 4);
}
//重复测试
@RepeatedTest(3)
@DisplayName("重复测试")
void repeatedTest() {
System.out.println("调用");
}
//组合测试
@Test
@DisplayName("测试组合断言")
void testAll() {
assertAll("测试item商品下单",
() -> {
//模拟用户余额扣减
assertTrue(1 < 2, "余额不足");
},
() -> {
//模拟item数据库扣减库存
assertTrue(3 < 4);
},
() -> {
//模拟交易流水落库
assertNotNull(new Object());
}
);
}
//测试超时
@Test
@Timeout(value = 3,unit = TimeUnit.SECONDS)
@DisplayName("超时测试")
void timeoutTest() {
System.out.println("超时测试");
}
三、高级特性
1、切片测试
@RunWith(SpringRunner.class)
@WebMvcTest(IndexController.class)
public class SpringBootTest {
@Autowired
private MockMvc mvc;
@Test
public void testExample() throws Exception {
//groupManager访问路径
//param传入参数
MvcResult result=mvc.perform(MockMvcRequestBuilders
.post("/groupManager")
.param("pageNum","1")
.param("pageSize","10"))
.andReturn();
MockHttpServletResponse response = result.getResponse();
String content = response.getContentAsString();
List<JtInfoDto> jtInfoDtoList = GsonUtils.toObjects(content,
new TypeToken<List<JtInfoDto>>() {}.getType());
for(JtInfoDto infoDto : jtInfoDtoList){
System.out.println(infoDto.getJtCode());
}
}
}
2、注解的使用
(1)配置类型
- @TestComponent:该注解是另一种@Component,在语义上用来指定某个Bean是专门用于测试的。该注解适用于测试代码和正式混合在一起时,不加载被该注解描述的Bean,使用不多。
- @TestConfiguration:该注解是另一种@TestComponent,它用于补充额外的Bean或覆盖已存在的Bean。在不修改正式代码的前提下,使配置更加灵活。
- @TypeExcludeFilters:用来排除@TestConfiguration和@TestComponent。适用于测试代码和正式代码混合的场景,使用不多。
- @OverrideAutoConfiguration:可用于覆盖@EnableAutoConfiguration,与ImportAutoConfiguration结合使用,以限制所加载的自动配置类。在不修改正式代码的前提下,提供了修改配置自动配置类的能力。
- @PropertyMapping:定义@AutoConfigure*注解中用到的变量名称,例如在@AutoConfigureMockMvc中定义名为的变量。一般不使用。
- 使用@SpringBootApplication启动测试或者生产代码,被@TestComponent描述的Bean会自动被排除掉。如果不是则需要向@SpringBootApplication添加TypeExcludeFilter。
(2)mock类型的注解
- @MockBean:用于mock指定的class或被注解的属性。
- @MockBeans:使@MockBean支持在同一类型或属性上多次出现。
- @SpyBean:用于spy指定的class或被注解的属性。
- @SpyBeans:使@SpyBean支持在同一类型或属性上多次出现
(3)自动配置类注解
- @AutoConfigureJdbc 自动配置JDBC
- @AutoConfigureCache 自动配置缓存
- @AutoConfigureDataLdap 自动配置LDAP
- @AutoConfigureJson 自动配置JSON
- @AutoConfigureJsonTesters 自动配置JsonTester
- @AutoConfigureDataJpa 自动配置JPA
- @AutoConfigureTestEntityManager 自动配置TestEntityManager
- @AutoConfigureRestDocs 自动配置Rest Docs
- @AutoConfigureMockRestServiceServer 自动配置 MockRestServiceServer
- @AutoConfigureWebClient 自动配置 WebClient
- @AutoConfigureWebFlux 自动配置 WebFlux
- @AutoConfigureWebTestClient 自动配置 WebTestClient
- @AutoConfigureMockMvc 自动配置 MockMvc
- @AutoConfigureWebMvc 自动配置WebMvc
- @AutoConfigureDataNeo4j 自动配置 Neo4j
- @AutoConfigureDataRedis 自动配置 Redis
- @AutoConfigureJooq 自动配置 Jooq
- @AutoConfigureTestDatabase 自动配置Test Database,可以使用内存数据库
(4)启动类注解
@SpringBootTest之外的注解都是用来进行切面测试的,他们会默认导入一些自动配。
- @SpringBootTest 自动侦测并加载@SpringBootApplication或@SpringBootConfiguration中的配置,默认web环境为MOCK,不监听任务端口
- @DataRedisTest 测试对Redis操作,自动扫描被@RedisHash描述的类,并配置Spring Data Redis的库
- @DataJpaTest 测试基于JPA的数据库操作,同时提供了TestEntityManager替代JPA的EntityManager
- @DataJdbcTest 测试基于Spring Data JDBC的数据库操作
- @JsonTest 测试JSON的序列化和反序列化
- @WebMvcTest 测试Spring MVC中的controllers
- @WebFluxTest 测试Spring WebFlux中的controllers
- @RestClientTest 测试对REST客户端的操作
- @DataLdapTest 测试对LDAP的操作
- @DataMongoTest 测试对MongoDB的操作
- @DataNeo4jTest 测试对Neo4j的操作
四、控制层接口测试
@Slf4j
@SpringBootTest
@AutoConfigureMockMvc //自动配置 MockMvc
class DemoControllerTest1 {
@Autowired
private MockMvc mock;
//测试get提交
@Test
void findById() throws Exception {
MvcResult mvcResult = mock.perform(MockMvcRequestBuilders.get("/demo/find/123").characterEncoding("UTF-8"))
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.jsonPath("$.code").value("S0000")) //比较json结果值
.andReturn();
MockHttpServletResponse response = mvcResult.getResponse();
response.setCharacterEncoding("UTF-8");
String content = response.getContentAsString();
log.info("findById Result: {}", content);
}
//测试post提交
@Test
void save() throws Exception {
MvcResult mvcResult = mock.perform(
MockMvcRequestBuilders.post("/demo/save")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.characterEncoding("UTF-8")
.content(JSONObject.toJSONString(new DemoVo("Hello World")))
)
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.jsonPath("$.code").value("S0000")) //比较json结果值
.andReturn();
MockHttpServletResponse response = mvcResult.getResponse();
response.setCharacterEncoding("UTF-8");
String content = response.getContentAsString();
log.info("save Result: {}", content);
}
}
参考:/myitnews/p/
/haixiang/p/