面试复盘:Junit 小白入门指南------从面试题到单测实践
在最近一次后端面试中,面试官问了我三个问题:"什么是 Junit?在 Spring Boot 项目中用到了 Junit 吗?你能写一段代码模拟一个接口的单测吗?"作为一名后端开发者,我顺利回答并写出了代码,但事后复盘时发现,有些细节对新手来说可能不太好理解,比如 MockBean
、when().thenReturn()
和 mockMvc.perform().andExpect()
是啥?这次我就以小白视角,详细复盘这些问题和代码,帮你从零基础搞懂 Junit 单测!
问题 1:什么是 Junit?
简单回答: Junit 是一个专门帮我们测试 Java 代码的工具。就像老师批改作业一样,它能检查你的代码是不是按预期工作。写代码时,我们用 Junit 写"测试用例",运行后就能知道哪里对了,哪里错了。
小白理解:
- 比如你写了个计算器程序,想确认"2 + 2"是不是等于 4,就可以用 Junit 写个测试,自动跑一遍,结果不对就报错。
- 它靠一些"标记"(注解,比如
@Test
)告诉电脑哪些是测试代码,还能用assertEquals
这种方法检查结果。
面试改进: 面试时我说 Junit 是"单元测试框架",其实可以加一句:"它是 Java 程序员的好帮手,能自动化验证代码,还跟 Spring Boot 配合得特别好!"
问题 2:在 Spring Boot 项目中用到了 Junit 吗?
简单回答: 用到了!Spring Boot 项目里,Junit 是默认的测试工具。我用它测过接口、业务逻辑和数据库操作。
小白理解:
- Spring Boot 是一个开发网站的框架,里面有很多"零件"(比如 Controller、Service),Junit 帮我们检查这些零件单独或一起工作时有没有问题。
- Spring Boot 自带了个
spring-boot-starter-test
的包,里面就包含 Junit 和其他测试工具,像个"测试套装"。
面试改进: 我会补充:"在 Spring Boot 里,我用 Junit 测试过接口有没有返回正确数据,比如查用户信息时,能不能返回正确的名字和 ID。"
问题 3:写一段代码模拟接口开发的单测
面试要求: 假设我开发了一个查询用户信息的接口,怎么用 Junit 写单测?
代码示例: 我写了一个简单的接口和测试代码,下面是完整版,后面会一步步拆解关键点。
java
// UserController.java(接口代码)
@RestController
@RequestMapping("/api/users")
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping("/{id}")
public ResponseEntity<User> getUserById(@PathVariable Long id) {
User user = userService.findUserById(id);
if (user == null) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(user);
}
}
// User.java(用户类)
public class User {
private Long id;
private String name;
public User(Long id, String name) {
this.id = id;
this.name = name;
}
// Getters 和 Setters 省略
}
// UserService.java(服务类)
@Service
public class UserService {
public User findUserById(Long id) {
return new User(id, "User-" + id); // 模拟查询
}
}
// UserControllerTest.java(测试代码)
@SpringBootTest
@AutoConfigureMockMvc
public class UserControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private UserService userService;
@Test
public void testGetUserById_Success() throws Exception {
Long userId = 1L;
User mockUser = new User(userId, "User-1");
when(userService.findUserById(userId)).thenReturn(mockUser);
mockMvc.perform(get("/api/users/{id}", userId))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(userId))
.andExpect(jsonPath("$.name").value("User-1"));
}
@Test
public void testGetUserById_NotFound() throws Exception {
Long userId = 999L;
when(userService.findUserById(userId)).thenReturn(null);
mockMvc.perform(get("/api/users/{id}", userId))
.andExpect(status().isNotFound());
}
}
小白拆解:关键概念详解 这代码里有几个"魔法"操作,新手可能会懵,下面我逐一解释。
1. @MockBean
是什么?
小白理解:
- 想象一下,
UserService
是去数据库找数据的"工人"。但测试时,我们不想真去数据库(太麻烦,还可能没数据),怎么办?@MockBean
就像雇了个"假工人",假装干活,实际啥也不干,全听你指挥。 - 在代码里,
@MockBean private UserService userService
告诉 Spring Boot:"别用真的 UserService,给我个假的,我要控制它!"
技术解释:
@MockBean
是 Spring Boot 测试里的注解,用来创建"模拟对象"(Mock),由 Mockito(一个模拟工具)支持。- 它会替换掉 Spring 容器里真正的
UserService
,让你自由定义它的行为。
为什么用它:
- 测试接口时,只关心接口逻辑,不想依赖数据库或其他服务,用
@MockBean
隔离依赖。
2. when().thenReturn()
是什么?
小白理解:
- 这个是给"假工人"下指令。比如
when(userService.findUserById(1L)).thenReturn(mockUser)
,意思是:"嘿,假的 UserService,如果有人问你 ID 是 1 的用户是谁,你就回答这个 mockUser,别干别的!" - 就像提前录好答案,测试时直接用。
技术解释:
when().thenReturn()
是 Mockito 的语法,用来设置模拟对象的行为。when(条件)
定义触发条件,thenReturn(结果)
指定返回值。- 比如:
when(userService.findUserById(1L)).thenReturn(new User(1L, "User-1"))
,表示调用findUserById(1L)
时返回假数据。
为什么用它:
- 控制测试环境,确保每次输入固定值时,输出是我们想要的,方便验证接口逻辑。
3. mockMvc.perform().andExpect()
在做什么?
小白理解:
MockMvc
就像一个"假浏览器",能假装访问你的接口。perform()
是"发送请求",比如get("/api/users/1")
就是访问http://localhost/api/users/1
。andExpect()
是"检查结果",比如status().isOk()
确认返回状态是 200,jsonPath("$.name").value("User-1")
检查返回的 JSON 里name
是不是 "User-1"。
技术解释:
MockMvc
是 Spring 提供的一个测试工具,用来模拟 HTTP 请求,不用真的启动服务器。perform()
执行请求,andExpect()
链式调用检查响应。- 常用检查:
status().isOk()
:状态码 200。status().isNotFound()
:状态码 404。jsonPath("$.字段").value(值)
:验证 JSON 数据。
代码例子解析:
java
mockMvc.perform(get("/api/users/{id}", userId))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(userId))
.andExpect(jsonPath("$.name").value("User-1"));
- 这段代码假装访问
/api/users/1
,然后检查:- 状态码是不是 200(成功)。
- 返回的 JSON 里
id
是不是 1。 name
是不是 "User-1"。
为什么用它:
- 测试接口时,模拟真实请求,检查返回结果是不是我们想要的,比直接调用方法更贴近用户体验。
复盘与新手建议
面试表现反思:
- 我回答了 Junit 的基本概念,也写出了代码,但没解释清楚这些"魔法"工具。对新手来说,这些细节很重要。
- 改进版回答:"Junit 是测试代码的工具,在 Spring Boot 里我用它测接口。像上面代码,我用
@MockBean
造了个假服务,用when().thenReturn()
控制返回值,再用MockMvc
假装访问接口,最后检查结果。"
给小白的建议:
- 从简单开始 :先写个
@Test
方法,用assertEquals
测试加法,跑通了再试复杂点的。 - 理解 Mock :把
@MockBean
想象成"替身演员",帮你省去麻烦的依赖。 - 多练 MockMvc :写个小接口,用
perform()
和andExpect()
测几次,熟悉检查状态码和 JSON。 - 工具配合:Junit 常跟 Mockito 和 Spring Test 一起用,别怕,慢慢学。
完整学习路径:
- 下载个 Spring Boot 项目,加
spring-boot-starter-test
依赖。 - 照着上面代码改改,跑跑看,熟悉报错和成功的感觉。
总结
这次面试让我意识到,Junit 不只是个工具,它背后还有很多"小助手"(像 Mockito 和 MockMvc)。对新手来说,理解 @MockBean
是造假对象、when().thenReturn()
是定规则、mockMvc.perform().andExpect()
是发请求检查结果,就能轻松上手单测。希望这篇博客能帮你搞懂 Junit,下次面试不慌!