You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 17:27:00