TDD 是什么?
测试驱动开发(Test-Driven Development,简称 TDD)是敏捷开发中的核心实践之一。它不仅仅是一种测试手段,更是一种设计方法论。其核心理念是在编写功能实现之前,先编写单元测试用例。通过测试来驱动整个开发过程,将需求分析、设计和质量控制量化到具体的测试代码中。
核心流程:红 - 绿 - 重构
TDD 的基本思路可以概括为三个步骤的循环:
- 红:编写一个失败的测试用例,明确需求。
- 绿:编写刚好能通过该测试的最小化代码。
- 重构:在不改变功能的前提下优化代码结构,遵循 DRY、OCP 等原则。
这个过程周而复始,直到项目完成。这种迭代方式能确保代码始终处于可运行状态,并具备良好的可维护性。
实战:Spring Boot 集成测试示例
在实际的 Java Web 开发中,我们常使用 Spring Boot 配合 MockMvc 进行接口测试。下面是一个典型的 UserController 测试类示例,展示了如何通过 TDD 思想覆盖增删改查及文件上传场景。
注意观察测试方法的命名规范(如 whenUploadSuccess),这有助于快速定位业务场景。同时,利用 MockMvc 模拟 HTTP 请求,无需启动完整服务器即可验证 Controller 层的逻辑。
/**
*/
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.fileUpload;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
org.springframework.http.MediaType;
org.springframework.mock.web.MockMultipartFile;
org.springframework.test.context.junit4.SpringRunner;
org.springframework.test.web.servlet.MockMvc;
org.springframework.test.web.servlet.setup.MockMvcBuilders;
org.springframework.web.context.WebApplicationContext;
{
WebApplicationContext wac;
MockMvc mockMvc;
{
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
}
Exception {
mockMvc.perform(fileUpload()
.file( (, , , .getBytes())))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString();
System.out.println(result);
}
Exception {
mockMvc.perform(get()
.param(, )
.param(, )
.param(, )
.param(, )
.contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(status().isOk())
.andExpect(jsonPath().value())
.andReturn().getResponse().getContentAsString();
System.out.println(result);
}
Exception {
mockMvc.perform(get()
.contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(status().isOk())
.andExpect(jsonPath().value())
.andReturn().getResponse().getContentAsString();
System.out.println(result);
}
Exception {
mockMvc.perform(get()
.contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(status().is4xxClientError());
}
Exception {
();
System.out.println(date.getTime());
+ date.getTime() + ;
mockMvc.perform(post()
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(content))
.andExpect(status().isOk())
.andExpect(jsonPath().value())
.andReturn().getResponse().getContentAsString();
System.out.println(reuslt);
}
Exception {
();
System.out.println(date.getTime());
+ date.getTime() + ;
mockMvc.perform(post()
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(content))
.andReturn().getResponse().getContentAsString();
System.out.println(reuslt);
}
Exception {
(LocalDateTime.now().plusYears().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
System.out.println(date.getTime());
+ date.getTime() + ;
mockMvc.perform(put()
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(content))
.andExpect(status().isOk())
.andExpect(jsonPath().value())
.andReturn().getResponse().getContentAsString();
System.out.println(reuslt);
}
Exception {
mockMvc.perform(delete()
.contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(status().isOk());
}
}

