本文最后更新于:2024年9月8日 晚上
Spring 测试
Junit
Junit是一个Java语言的单元测试框架,被开发者用于实施对应用程序的单元测试,加快程序编制速度,同时提高编码的质量。
注解
1 2 3 4 5 6 public class TestDemo { @Test void fun1 () { System.out.println("测试" ); } }
注意 :对于Junit4而言,所有的测试方法应当是public声明的,而Junit5不用,只不过不同的版本,这个@Test的类是不同的:
1 2 Junit4: org.junit.Test Junit5: org.junit.jupiter.api.Test
注解
Description
@Test
写在一个测试类中的测试方法中的元注解,也就是说,在每一个单元测试方法上都应加上它才会生效
@BeforeEach
在Junit4中,这个注解叫@Before,就是会在每一个测试方法执行前都会执行的方法,包括@Test
, @RepeatedTest
, @ParameterizedTest
,或者 @TestFactory
注解的方法
@BeforeAll
在当前测试类中的方法执行前执行,只会执行一次,在Junit4中是@Before
@AfterAll
在当前测试类中的所有测试方法执行完之后执行,只会执行一次,在Junit4中是@After
@AfterEach
和上边很相似,在Junit4中,这个注解叫@After,就是会在每一个测试方法执行之后都会执行的方法,包括@Test
, @RepeatedTest
, @ParameterizedTest
,或者@TestFactory
注解的方法
@ParameterizedTest
参数化测试,就是在你的测试方法执行时,自动添加一些参数
@RepeatedTest
重复此测试方法
@TestFactory
动态测试的工厂方法
@TestTemplate
测试模板
@TestMethodOrder
测试方法的执行顺序,默认是按照代码的前后顺序执行的
@DisplayName
自定义测试方法的名称显示
@DisplayNameGeneration
自定义名称生成器
@Nested
表示一个非静态的测试方法,也就是说@BeforeAll和@AfterAll对此方法无效,如果单纯地执行此方法,并不会触发这个类中的@BeforeAll和@AfterAll方法
@Tag
自定义tag,就是可以自定义一个属于自己的@Test一样功能的注解
@Disabled
表明此方法不可用,并不会执行,在JUnit4中的@Ignore
@Timeout
设定方法执行的超时时间,如果超过,就会抛出异常
Spring
pom.xml
1 2 3 4 5 6 7 8 9 10 11 <dependency > <groupId > org.springframework</groupId > <artifactId > spring-test</artifactId > <version > 5.2.5.RELEASE</version > </dependency > <dependency > <groupId > org.junit.jupiter</groupId > <artifactId > junit-jupiter-api</artifactId > <version > 5.8.1</version > <scope > compile</scope > </dependency >
测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 @SpringJUnitConfig @ContextConfiguration("classpath:application.xml") public class SpringTest { @Resource private Teacher teacher; @Test void fun () { System.out.println(teacher.getName()); } }
Spring Boot
在SpringBoot中,为我们提供了一个SpringBootTest的注解来加载Spring容器。
在SpringBoot2.2.0以前是JUnit4,在SpringBoot之后是JUnit5
pom.xml
1 2 3 4 5 6 7 <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-test</artifactId > <scope > test</scope > </dependency > </dependencies >
测试类
1 2 3 4 5 6 7 8 @SpringBootTest public class TestDemo { @Test void contextLoad () { System.out.println("Hello World!" ); } }
为什么在SpringBoot中不用指定Spring容器的配置文件?
其实是会自动加载类路径下的那个SpringBoot的启动类的,就算指定配置文件,也是指定那个启动类为配置类。
如果你写的包结构不符合它的要求,就需要自己使用@ContextConfiguration
注解来指定Spring的配置类了。
断言
使用Assertions工具类可判断程序运行结果是否正确。
1 2 3 4 5 6 7 8 9 10 @Test void contextLoad () { String expected = "ABC" ; String actual = "ABB" ; Assertions.assertNotNull(actual, "结果不为空!" ); Assertions.assertEquals(expected, actual, "真实值与预期值不符合!" ); Assertions.assertSame(expected, actual, "不是同一个对象!" ); Assertions.assertTrue(1 + 1 == 2 , "表达式为False" ); Assertions.assertFalse(1 + 1 != 2 , "表达式为True" ); }
参数化测试
参数化测试可以用不同的参数多次运行测试,它们和普通的@Test
方法一样声明,但是使用@ParameterizedTest
注解,另外必须声明至少一个将为每次调用提供参数的来源(source)
1 2 3 4 5 @ParameterizedTest @ValueSource(strings = { "racecar", "radar", "able was I ere I saw elba" }) void palindromes (String candidate) { assertTrue(isPalindrome(candidate)); }
@ValueSource
@ValueSource
是最简单的source之一,它可以让你指定一个原生类型(String,int,long或double)的数组,并且只能为每次调用提供一个参数。
1 2 3 4 5 @ParameterizedTest @ValueSource(ints = { 1, 2, 3 }) void testWithValueSource (int argument) { assertNotNull(argument); }
@EnumSource
@EnumSource
提供了一个使用Enum
常量的简便方法,该注释提供了一个可选的name
参数,可以指定使用哪些常量,如果省略,所有的常量将被用在下面的例子中。
1 2 3 4 5 6 7 8 9 10 11 @ParameterizedTest @EnumSource(TimeUnit.class) void testWithEnumSource (TimeUnit timeUnit) { assertNotNull(timeUnit); }@ParameterizedTest @EnumSource(value = TimeUnit.class, names = { "DAYS", "HOURS" }) void testWithEnumSourceInclude (TimeUnit timeUnit) { assertTrue(EnumSet.of(TimeUnit.DAYS, TimeUnit.HOURS).contains(timeUnit)); }
@MethodSource
@MethodSource
允许你引用一个或多个测试类的工厂方法,这样的方法必须返回一个Stream
,Iterable
,Iterator
或者参数数组,另外,这种方法不能接受任何参数,默认情况下,除非测试类用@TestInstance(Lifecycle.PER_CLASS)
注解,否则这些方法必须是静态的。
如果只需要一个参数,则可以返回参数类型的实例Stream
,如以下示例所示。
1 2 3 4 5 6 7 8 9 @ParameterizedTest @MethodSource("stringProvider") void testWithSimpleMethodSource (String argument) { assertNotNull(argument); }static Stream<String> stringProvider () { return Stream.of("foo" , "bar" ); }
支持原始类型(DoubleStream
,IntStream
和LongStream
)的流,示例如下:
1 2 3 4 5 6 7 8 9 @ParameterizedTest @MethodSource("range") void testWithRangeMethodSource (int argument) { assertNotEquals(9 , argument); }static IntStream range () { return IntStream.range(0 , 20 ).skip(10 ); }
如果测试方法声明多个参数,则需要返回一个集合或Arguments
实例流,如下所示,请注意,Arguments.of(Object…)
是Arguments
接口中定义的静态工厂方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @ParameterizedTest @MethodSource("stringIntAndListProvider") void testWithMultiArgMethodSource (String str, int num, List<String> list) { assertEquals(3 , str.length()); assertTrue(num >=1 && num <=2 ); assertEquals(2 , list.size()); }static Stream<Arguments> stringIntAndListProvider () { return Stream.of( Arguments.of("foo" , 1 , Arrays.asList("a" , "b" )), Arguments.of("bar" , 2 , Arrays.asList("x" , "y" )) ); }
Mock MVC
MockMvc是由spring-test包提供,实现了对Http请求的模拟,能够直接使用网络的形式,转换到Controller的调用,使得测试速度快,不依赖网络环境,同时提供了一套验证的工具,结果的验证十分方便。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @SpringBootTest @AutoConfigureMockMvc class TallyApplicationTests { @Resource MockMvc mockMvc; @Test void testSingIn () throws Exception { MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.post("/user/signIn" ) .param("username" ,"admin" ) .param("password" ,"123456" )) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.jsonPath("code" ).value(200 )) .andDo(MockMvcResultHandlers.print()) .andReturn(); } }
.andExpect()
:设置预期,返回数据需要符合设定的预期值。