Spring 测试

本文最后更新于: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
// 指定配置文件路径,会先从test域中找。
@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,IntStreamLongStream)的流,示例如下:
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():设置预期,返回数据需要符合设定的预期值。

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!