MockMvc测试含实体与MultipartFile的接口失败及序列化问题
用户基于Spring Boot实现了KycController接口,通过@PostMapping("/ekyc")接收带@Valid注解的@ModelAttribute KycEntity实体(包含MultipartFile类型的imageFile字段),完成文件存储与实体入库逻辑。编写测试用例时遇到两个核心问题:
1. 测试用例执行失败
控制台输出显示后端接收的实体所有属性均为null,触发全部必填字段的校验错误:
null true [must not be null, State is required, must not be null, Address is required, Pincode is required, must not be null, must not be null, Num is required, Last name is required, must not be null, City is required, must not be null, Address is required, must not be null, must not be null, Middle name is required, First name is required, Image URL is required, must not be null, must not be null, must not be null]
2. MultipartFile序列化问题
使用ObjectMapper序列化含MultipartFile字段的KycEntity时,imageFile字段始终为null,无法正常序列化。
一、修复测试用例参数传递问题
你的Controller通过@ModelAttribute接收表单数据,同时包含文件上传,属于multipart/form-data类型请求,而非JSON请求。测试时不能用contentType(MediaType.APPLICATION_JSON)构造请求,必须使用MockMvcRequestBuilders.multipart(),通过param()传递实体字段、file()传递文件。
修改后的完整测试用例代码:
class EkycControllerTest { private MockMvc mockMvc; @InjectMocks private KycController controller; @Mock private KycRepo repo; // 必须Mock仓库,避免空指针 @Mock private KycService kycService; @BeforeEach public void setUp() { MockitoAnnotations.initMocks(this); mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); } @Test void testInsertApiWithValidData() throws Exception { // 构造测试用的模拟文件 MockMultipartFile imageFile = new MockMultipartFile("imageFile", "image.jpg", MediaType.IMAGE_JPEG_VALUE, "image content".getBytes()); // 构造multipart请求,逐个传递实体字段与文件 mockMvc.perform(MockMvcRequestBuilders.multipart("/ekyc") // 传递KycEntity的各个属性 .param("firstName", "John") .param("middleName", "Doe") .param("lastName", "Smith") .param("email", "john.doe@example.com") .param("state", "State") .param("city", "City") .param("num", "1234567890") .param("add", "123 Main St") .param("add2", "Apt 2B") .param("pincode", "123456") .param("image", "image_url.jpg") // 传递文件 .file(imageFile) .contentType(MediaType.MULTIPART_FORM_DATA)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().string("Insert successful")); // 验证仓库的save方法是否被调用 verify(repo, times(1)).save(any(KycEntity.class)); } }
关键说明
@ModelAttribute接收的是表单字段,而非JSON结构,因此测试时需用param()逐个传递实体属性,不能直接传JSON内容。- 必须Mock
KycRepo,否则Controller中调用repo.save()会抛出空指针异常。 - 用
MockMvcRequestBuilders.multipart()构造文件上传请求,并指定contentType(MediaType.MULTIPART_FORM_DATA)。
二、解决MultipartFile序列化问题
MultipartFile是Spring定义的接口,本质是上传的文件流,本身不支持JSON序列化,且你的业务场景也不需要序列化该字段:
1. 实体类优化
KycEntity中的imageFile是临时接收文件的字段,不需要持久化到数据库,也不需要序列化。给该字段添加注解忽略序列化与持久化:
public class KycEntity { // 其他字段... @Transient // JPA注解:忽略该字段,不存入数据库 @JsonIgnore // Jackson注解:序列化时忽略该字段 private MultipartFile imageFile; // getter、setter方法... }
2. 测试场景优化
测试时通过param()+file()的方式传递数据,完全避开MultipartFile的序列化问题,无需尝试将其转为JSON。
内容的提问来源于stack exchange,提问作者Apurv Garg

