Spring Boot CSV导出功能的Junit测试编写求助
测试实现方案
前置修复
你现有代码存在几处笔误,需要先修正才能正常运行:
ExampleRepository中findByName方法返回值应为List<Example>,你写的List<Report>属于类名错误- Controller1中调用Service的变量名拼写错误,
examplesService改为exampleService - Controller2中
exampleService.findByname改为exampleService.findByName,忽略字段配置里的Report.class改为Example.class
测试思路
采用Spring Boot的@WebMvcTest切片测试方案,仅加载控制器相关组件,用Mockito模拟Service层返回值,通过MockMvc发起HTTP请求,直接验证响应头、CSV内容是否符合预期,无需启动完整应用或依赖真实数据库,执行效率高。
依赖配置
确保你的pom.xml(Maven)或build.gradle(Gradle)已引入Spring Boot测试启动器,一般新建Spring Boot项目默认会自带:
<!-- Maven 依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
测试类代码
在src/test/java/com/example目录下新建测试类CsvExportTest.java:
package com.example; import com.example.model.Example; import com.example.services.ExampleService; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.web.servlet.MockMvc; import java.util.List; import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; // 加载两个控制器对应的Bean @WebMvcTest(controllers = {com.example.controllers.Controller1.class, com.reports.controllers.Controller2.class}) public class CsvExportTest { @Autowired private MockMvc mockMvc; // 模拟Service层,无需依赖真实数据库 @MockBean private ExampleService exampleService; // 测试全字段导出接口 @Test public void testFullFieldCsvExport() throws Exception { // 构造模拟返回数据 Example e1 = new Example(); e1.setId(1L); e1.setName("abc"); e1.setCity("北京"); e1.setAmount("100"); e1.setCountry("中国"); Example e2 = new Example(); e2.setId(2L); e2.setName("abc"); e2.setCity("上海"); e2.setAmount("200"); e2.setCountry("中国"); // 模拟Service调用返回结果 when(exampleService.findByName("abc")).thenReturn(List.of(e1, e2)); // 发起请求并验证结果 mockMvc.perform(get("/demo/result").param("name", "abc")) .andExpect(status().isOk()) .andExpect(content().contentType("text/csv")) .andExpect(header().string("Content-Disposition", "attachment; filename=\"names.csv\"")) // 验证CSV表头和内容符合预期,可根据实际字段顺序调整 .andExpect(content().string(org.hamcrest.Matchers.containsString("id,city,name,amount,country"))) .andExpect(content().string(org.hamcrest.Matchers.containsString("1,北京,abc,100,中国"))) .andExpect(content().string(org.hamcrest.Matchers.containsString("2,上海,abc,200,中国"))); } // 测试指定列导出接口 @Test public void testSpecifiedColumnCsvExport() throws Exception { // 构造模拟返回数据 Example e1 = new Example(); e1.setId(1L); e1.setAmount("100"); e1.setName("abc"); Example e2 = new Example(); e2.setId(2L); e2.setAmount("200"); e2.setName("abc"); when(exampleService.findByName("abc")).thenReturn(List.of(e1, e2)); mockMvc.perform(get("/example/output").param("name", "abc")) .andExpect(status().isOk()) .andExpect(content().contentType("text/csv")) .andExpect(header().string("Content-Disposition", "attachment; filename=\"details.csv\"")) // 验证仅返回id和amount两列 .andExpect(content().string(org.hamcrest.Matchers.containsString("id,amount"))) .andExpect(content().string(org.hamcrest.Matchers.containsString("1,100"))) .andExpect(content().string(org.hamcrest.Matchers.containsString("2,200"))) // 验证其他字段不会被导出 .andExpect(content().string(org.hamcrest.Matchers.not(org.hamcrest.Matchers.containsString("city")))) .andExpect(content().string(org.hamcrest.Matchers.not(org.hamcrest.Matchers.containsString("name")))) .andExpect(content().string(org.hamcrest.Matchers.not(org.hamcrest.Matchers.containsString("country")))); } }
补充说明
如果你的opencsv配置了自定义的表头顺序、分隔符,调整测试里的内容验证逻辑匹配实际输出即可。如果需要做全链路集成测试,可以把@WebMvcTest换成@SpringBootTest搭配@AutoConfigureMockMvc,会加载完整Spring上下文调用真实Service和Repository,这种情况建议搭配H2等内存测试数据库使用,避免污染正式库数据。
内容的提问来源于stack exchange,提问作者swarajsingh78
相关产品推荐
相关产品推荐

