一、前言
在我们日常开发中项目功能自测必不可少,但是又是很容易被忽视的一个环节,其实,个人认为测试才是一个项目良好运行的保障,好的测试习惯能帮我们避免很多问题,可以提高我们的思考和开发功能的效率,但是一个复杂的项目的测试往往是让人头痛不已,千丝万缕连在一起,除非还原用户使用场景,否则怎么测试都让程序员感到不安,往往写完代码提交之后寄希望于测试爸爸能测出漏洞,但是自己写的代码,薄弱点和漏洞出现的可能性也只有自己亲自知道该往那个方向测试重拳出击,测试又怎么会知道呢?
往往项目上线之后我们还如履薄冰,要怎么测试自己开发的功能一直以来都是每个开发工作者需要考虑的问题,但是测试又分很多种类,比如一个小小的逻辑模块不依赖于任何模块的测试,像我来说就一个main方向就搞定了,如果在依赖深一点的,需要配置文件,需要web容器,需要bean的嵌套,但是又没有完整的环境,或者说配置一套完整的环境实在是太麻烦的时候,我们应该怎么测试呢?
对了,如果你刚好是SpringBoot项目,那么你一定要了解一下SpringBootTest
,在SpringBoot中集成Junit5来进行测试,这也是目前市场主流的测试框架。
二、快速使用SpringBootTest
1、Junit集成SpringBoot
SpringBoot2.2.x 之前使用的是Junit4,之后就使用的是Junit5。
maven引入依赖,仅需要引入starter依赖就足够了。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.3.13.RELEASE</version>
<scope>test</scope>
</dependency>
2、一个简单的测试类
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class DemoTest {
@Test
public void demoTest()
{
System.out.println("test success");
}
}
三、SpringTest 注解
Spring为了简化xml文件配置,使用了大量的注解,所以需要我们重点了解SpringBootTest
的注解,以便了解SpringBootTest
的运行机制。
@SpringBootTest
它会加载完整的Spring应用程序上下文,包括所有的bean定义、配置和组件,并且会自动启动嵌入式的服务器。
@SpringBootTest 参数配置
1、value
指定”my.application.property
“的值为”value”
@SpringBootTest(value = "my.application.property=value")
2、properties
在加载配置的时候修改my.property my.otherProperty
@SpringBootTest(properties = {"my.property=value1", "my.otherProperty=value2"})
3、classes
指定两个配置类MyConfig1.class
和MyConfig2.class
@SpringBootTest(classes = {MyConfig1.class, MyConfig2.class})
4、webEnvironment
指定使用随机端口的Web环境进行集成测试。
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)

@Test
用来标记这个方法是个测试方法。
@SpringBootTest
public class DemoTest {
/**
* 表示这个方法是个测试方法
*/
@Test
public void demoTest()
{
System.out.println("test success");
}
}
@ParameterizedTest
用来标记一个参数化测试方法,和以下注解搭配使用。(列出常用的几种入参方式注解)
-
@ValueSource: 用于指定基本类型、String类型或Class类型的参数值。 -
@CsvSource: 用于指定CSV格式的参数值,逗号分隔每个参数。 -
@MethodSource: 用于指定一个或多个方法作为参数提供者。 -
@ArgumentsSource: 用于指定一个自定义的参数提供者类。 -
@NullSource: 用于指定null值作为参数。 -
@EmptySource: 用于指定空值作为参数。 -
@NullAndEmptySource: 用于指定null值和空值作为参数。 -
@DisplayNameGeneration: 用于指定一个自定义的显示名称生成器。
这些注解提供了不同的方式来为测试方法提供参数,并且可以根据实际情况选择合适的注解来进行参数化测试。
public class DemoTest {
/**
* @ParameterizedTest标记名为testIsPositive的参数化测试方法
* @ValueSource注解,我们将整数1、2和3作为参数传递给测试方法
* @param number
*/
@ParameterizedTest
@ValueSource(ints = {1, 2, 3})
public void testIsPositive(int number) {
assertTrue(number > 0);
}
}
1、@ValueSource
用于提供测试方法的参数化值。
public class CalculatorTest {
@ParameterizedTest
@ValueSource(ints = {1, 2, 3, 4, 5})
public void testIsPositive(int number) {
assertTrue(number > 0);
}
}
2、@MethodSource
用于提供测试方法的参数化方法。
public class CalculatorTest {
@ParameterizedTest
@MethodSource("provideAdditionTestData")
public void testAddition(int a, int b, int expected) {
Calculator calculator = new Calculator();
int result = calculator.add(a, b);
assertEquals(expected, result);
}
private static Stream<Arguments> provideAdditionTestData() {
return Stream.of(
Arguments.of(1, 2, 3),
Arguments.of(5, -3, 2),
Arguments.of(10, 10, 20)
);
}
}
3、@NullSource
用于指定测试方法的参数化测试中的一个参数为null。
public class StringUtilsTest {
@ParameterizedTest
@NullSource
public void testIsEmpty_Null(String input) {
assertTrue(StringUtils.isEmpty(input));
}
}
4、@EnumSource
用于指定测试方法的参数化测试中的一个参数为枚举类型的值。
public class CalculatorTest {
enum Operation {
ADD, SUBTRACT, MULTIPLY, DIVIDE
}
@ParameterizedTest
@EnumSource(Operation.class)
public void testCalculate(Operation operation) {
Calculator calculator = new Calculator();
int result;
switch (operation) {
case ADD:
result = calculator.add(2, 3);
assertEquals(5, result);
break;
case SUBTRACT:
result = calculator.subtract(5, 2);
assertEquals(3, result);
break;
case MULTIPLY:
result = calculator.multiply(4, 6);
assertEquals(24, result);
break;
case DIVIDE:
result = calculator.divide(10, 2);
assertEquals(5, result);
break;
}
}
}
@RepeatedTest
用于重复运行相同的测试方法。可以使用该注解指定要重复运行的次数。
public class DemoTest {
/**
* @RepeatedTest(5) 标记名为testAddition的测试方法,并指定要重复运行它的次数为5次
*/
@RepeatedTest(5)
public void testAddition() {
int result = 2 + 2;
assertEquals(4, result);
}
}
@DisplayName
用于为测试类或测试方法指定一个自定义的显示名称。
@DisplayName("Calculator Tests")
public class CalculatorTest {
@Test
@DisplayName("Addition Test")
public void testAddition() {
int result = Calculator.add(2, 2);
assertEquals(4, result);
}
@Test
@DisplayName("Subtraction Test")
public void testSubtraction() {
int result = Calculator.subtract(5, 3);
assertEquals(2, result);
}
}
@BeforeEach & @AfterEach & @BeforeAll & @AfterAll
-
@BeforeEach 在每个测试方法运行之前执行一次。 -
@AfterEach 在每个测试方法运行之后执行一次。 -
@BeforeAll 在所有测试方法之前执行一次。 -
@AfterAll 在所有测试方法之前执行一次。
public class DemoTest {
@BeforeAll
public static void init() {
System.out.println("@BeforeAll");
}
@BeforeEach
public void setUp() {
System.out.println("@BeforeEach");
}
@Test
public void testAddition() {
System.out.println("Test success");
}
@AfterEach
public void tearDown() {
System.out.println("@AfterEach");
}
@AfterAll
public static void cleanUp() {
System.out.println("@AfterAll");
}
}
结果

@Disabled
用于禁用测试类或测试方法。
@Disabled("This test is currently disabled")
public class CalculatorTest {
@Test
public void testAddition() {
}
}
@Timeout
它用于设置测试方法的超时时间。
public class CalculatorTest {
@Test
@Timeout(value = 5, unit = TimeUnit.SECONDS)
public void testAddition() {
// 执行需要在5秒内完成的测试代码
}
}
四、Junit5断言
JUnit Jupiter 断言都是 static org.junit.jupiter.Assertions
方法,方便使用。
assertEquals(expected, actual)
验证两个值是否相等。
public class DemoTest {
@Test
public void test() {
int expected = 10;
int actual = 5 + 5;
assertEquals(expected, actual); // 通过
}
}
assertNotEquals(unexpected, actual)
验证两个值是否不相等。
public class DemoTest {
@Test
public void test() {
int unexpected = 10;
int actual = 5 + 5;
assertNotEquals(unexpected, actual); // 通过
}
}
assertArrayEquals(expectedArray, actualArray)
验证两个数组是否相等。
public class DemoTest {
@Test
public void test() {
int[] expectedArray = {1, 2, 3};
int[] actualArray = {1, 2, 3};
assertArrayEquals(expectedArray, actualArray); // 通过
}
}
assertTrue(condition)
验证条件是否为true。
public class DemoTest {
@Test
public void test() {
boolean condition = 5 > 3;
assertTrue(condition); // 通过
}
}
assertFalse(condition)
验证条件是否为false。
public class DemoTest {
@Test
public void test() {
boolean condition = 5 < 3;
assertFalse(condition); // 通过
}
}
assertNull(actual)
验证值是否为null。
public class DemoTest {
@Test
public void test() {
String actual = null;
assertNull(actual); // 通过
}
}
assertNotNull(actual)
验证值是否不为null。
public class DemoTest {
@Test
public void test() {
String actual = "Hello";
assertNotNull(actual); // 通过
}
}
assertSame(expected, actual)
验证两个引用是否指向同一个对象。
public class DemoTest {
@Test
public void test() {
String expected = "Hello";
String actual = "Hello";
assertSame(expected, actual); // 通过
}
}
assertNotSame(unexpected, actual)
验证两个引用是否指向不同的对象。
public class DemoTest {
@Test
public void test() {
String unexpected = "Hello";
String actual = "World";
assertNotSame(unexpected, actual); // 通过
}
}
assertThrows(expectedType, executable)
验证代码块是否抛出了指定的异常。
public class DemoTest {
@Test
public void test() {
assertThrows(ArithmeticException.class, () -> {
int result = 1 / 0; // 抛出ArithmeticException
});
}
}
assertDoesNotThrow(executable)
验证代码块是否没有抛出任何异常。
public class DemoTest {
@Test
public void test() {
assertDoesNotThrow(() -> {
int result = 1 / 1; // 不会抛出异常
});
}
}
assertTimeout(duration, executable)
验证代码块是否在指定的时间内执行完毕。
public class DemoTest {
@Test
public void test() {
assertTimeout(Duration.ofSeconds(5), () -> {
// 执行耗时较长的代码块
});
}
}
assertAll(executables)
验证多个断言是否都通过。
public class DemoTest {
@Test
public void test() {
assertAll("numbers",
() -> assertEquals(1, 1),
() -> assertEquals(2, 2),
() -> assertEquals(3, 3)
);
}
}
assertTimeout(duration, executable)
用于在指定的时间内执行一个代码块,并在超时时抛出异常。
public class ExampleTest {
@Test
public void testMethod() {
assertTimeout(Duration.ofSeconds(2), () -> {
// 执行耗时较长的代码块,不超过2秒
Thread.sleep(1000); // 模拟耗时操作
});
}
}
fail()
用于在测试中直接失败并抛出一个AssertionError
异常。
public class ExampleTest {
@Test
public void testMethod() {
assertTimeout(Duration.ofSeconds(2), () -> {
// 执行耗时较长的代码块,不超过2秒
Thread.sleep(1000); // 模拟耗时操作
});
}
}
五、MockMvc
用于对Controller
进行单元测试,MockMvc使用了Spring的TestContext
框架来创建一个测试上下文,其中包括模拟的Servlet容器。它会加载应用程序的配置,并创建一个模拟的DispatcherServlet
实例来处理请求。
MockMvc提供了一种模拟请求和验证响应的方式,可以在不启动Web服务器的情况下对Controller
进行测试。它可以模拟HTTP请求,包括GET、POST、PUT、DELETE
等请求方法,并验证Controller
返回的响应结果。
@SpringBootTest
@AutoConfigureMockMvc
public class DemoTest {
@Autowired
private MockMvc mockMvc;
@BeforeEach
public void setup() {
// 在每个测试方法执行前进行一些初始化操作
}
@Test
public void testGetMethod() throws Exception {
/**
* get请求
*/
MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.get("/example") // 发起GET请求,访问路径为"/example"
.accept(MediaType.APPLICATION_JSON)// 接受JSON格式的响应
.param("id", "123") //参数
.param("first_flag", String.valueOf(true)); //参数
MvcResult result = mockMvc.perform(requestBuilder)
.andExpect(MockMvcResultMatchers.status().isOk()) // 验证请求的HTTP状态码为200
.andExpect(MockMvcResultMatchers.jsonPath("$.message").value("success")) // 验证响应中的JSON字段"message"的值为"success"
.andReturn();// 返回MockMvcResult对象
MockHttpServletResponse response = result.getResponse(); //得到返回值
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); //设置响应 Content-Type
System.out.println(response); // 打印
}
}
MockMvcRequestBuilders
MockMvcRequestBuilders
是一个用于构建MockHttpServletRequestBuilder
对象的工具类。MockHttpServletRequestBuilder
是MockMvc框架中用于构建模拟HTTP请求的请求构建器。
一些常用的MockMvcRequestBuilders
方法包括:
get
MockHttpServletRequestBuilder getRequest = MockMvcRequestBuilders.get("/api/users");
post
MockHttpServletRequestBuilder postRequest = MockMvcRequestBuilders.post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content("{"username": "john", "password": "123456"}");
put
MockHttpServletRequestBuilder putRequest = MockMvcRequestBuilders.put("/api/users/1")
.contentType(MediaType.APPLICATION_JSON)
.content("{"username": "john", "password": "654321"}");
delete
MockHttpServletRequestBuilder deleteRequest = MockMvcRequestBuilders.delete("/api/users/1");
总结
一定要根据自己的实际情况和业务来测试自己的代码,快去试试吧!
来源:juejin.cn/post/7296373915542601762
后端专属技术群
构建高质量的技术交流社群,欢迎从事编程开发、技术招聘HR进群,也欢迎大家分享自己公司的内推信息,相互帮助,一起进步!
文明发言,以
交流技术
、职位内推
、行业探讨
为主
广告人士勿入,切勿轻信私聊,防止被骗

加我好友,拉你进群
原文始发于微信公众号(Java知音):【SpringBoot】 Test & Junit5 看这一篇就足够了
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/296203.html