单元测试:是“浪费时间”,还是“救命稻草”?——聊聊JUnit与Mockito
开篇语
哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云/阿里云/华为云/51CTO;欢迎大家常来逛逛
今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。
我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,希望以这种方式帮助到更多的初学者或者想入门的小伙伴们,同时也能对自己的技术进行沉淀,加以复盘,查缺补漏。
小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持!
前言
不得不承认,刚入行的时候,我对单元测试的感觉就是:**能跑就行,写啥测试?**🙃 结果上线两天就被 bug 打脸,修复的时间比写测试还要久三倍。那一刻我才悟:单元测试不是写给机器看的,是写给“未来的自己”看的,不然改需求的时候你自己都会想打自己。
今天我们就来聊聊单元测试里最常见的两个“神器”:JUnit 和 Mockito,再顺便看看它们在 Spring 测试里的组合拳。
1. JUnit框架概述与使用
JUnit 是 Java 世界里最常用的测试框架。它的目标很简单:让你写的测试能跑起来,还能自动验证对不对。
核心注解:
@Test
:标记一个测试方法。@BeforeEach
:每个测试方法执行前跑一次。@AfterEach
:每个测试方法执行后跑一次。@BeforeAll
:在所有测试方法前执行(通常用来做全局初始化)。@AfterAll
:在所有测试方法后执行(通常做资源释放)。
代码案例:
import org.junit.jupiter.api.*;
class Calculator {
int add(int a, int b) { return a + b; }
}
public class CalculatorTest {
private Calculator calc;
@BeforeEach
void setUp() {
calc = new Calculator();
System.out.println("测试前初始化");
}
@Test
void testAdd() {
Assertions.assertEquals(5, calc.add(2, 3));
}
@AfterEach
void tearDown() {
System.out.println("测试完成,清理");
}
}
👉 小结:JUnit 就像健身房里的跑步机,简单、重复、看似无聊,但关键时刻能救你命。
2. 测试生命周期与断言
生命周期
- 初始化 → 执行测试 → 清理环境
- 就像你做实验:先布置实验桌 → 进行实验 → 实验完收拾。
常用断言(Assertions)
assertEquals(expected, actual)
assertTrue(condition)
assertThrows(Exception.class, () -> { ... })
举个例子:
@Test
void testDivideByZero() {
ArithmeticException ex = Assertions.assertThrows(
ArithmeticException.class,
() -> { int x = 1 / 0; }
);
Assertions.assertEquals("/ by zero", ex.getMessage());
}
👉 用断言的好处:你不用盯着控制台 print,看着红绿灯就知道过没过。
3. Mockito与Mock对象
现实开发中,很多类依赖外部服务,比如数据库、网络请求。难道写测试要真去连数据库?不现实!这时候 Mockito 就派上用场了,它可以“假装”一个对象,模拟方法返回值。
案例:
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import static org.mockito.Mockito.*;
interface UserService {
String getUserName(int id);
}
class UserController {
private UserService service;
UserController(UserService service) { this.service = service; }
String getUser(int id) { return service.getUserName(id); }
}
public class UserControllerTest {
@Test
void testGetUser() {
UserService mockService = Mockito.mock(UserService.class);
when(mockService.getUserName(1)).thenReturn("Alice");
UserController controller = new UserController(mockService);
Assertions.assertEquals("Alice", controller.getUser(1));
verify(mockService).getUserName(1); // 验证是否被调用
}
}
👉 Mockito 就像“替身演员”:数据库、接口太麻烦?没事儿,找个替身来跑戏!
4. 集成测试与Spring Test
单元测试解决的是小模块的正确性,但 Spring 这种庞然大物,光靠单元测试还不够,还得上集成测试。
Spring Boot 提供的测试支持
@SpringBootTest
:加载整个 Spring 容器。@WebMvcTest
:专门测 Controller 层。@MockBean
:结合 Mockito,mock 容器里的 Bean。
案例:
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;
import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@WebMvcTest(UserController.class)
class UserControllerIntegrationTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private UserService userService;
@Test
void testGetUser() throws Exception {
when(userService.getUserName(1)).thenReturn("Bob");
mockMvc.perform(get("/user/1"))
.andExpect(status().isOk())
.andExpect(content().string("Bob"));
}
}
👉 有了 Spring Test,你就可以在不启动整个服务器的情况下,模拟 HTTP 请求,简直就是“本地调试神器”。
结语:写测试,到底值不值?
很多人觉得单元测试浪费时间,但真相是:写测试是给未来的自己买保险。JUnit 帮你规范地测逻辑,Mockito 帮你轻松 mock 依赖,Spring Test 帮你验证整体流程。
问题来了:下次你改需求的时候,是要勇敢上线,还是先写几个测试来保命?😉
… …
文末
好啦,以上就是我这期的全部内容,如果有任何疑问,欢迎下方留言哦,咱们下期见。
… …
学习不分先后,知识不分多少;事无巨细,当以虚心求教;三人行,必有我师焉!!!
wished for you successed !!!
⭐️若喜欢我,就请关注我叭。
⭐️若对您有用,就请点赞叭。
⭐️若有疑问,就请评论留言告诉我叭。
版权声明:本文由作者原创,转载请注明出处,谢谢支持!
- 点赞
- 收藏
- 关注作者
评论(0)