使用Junit与Mockito测试Spring Boot Multipart POST请求空指针问题咨询
问题根因
你测试代码中使用@MockBean声明的PhotoService是Mock对象,未对addPhoto方法的返回值做Stub(打桩)处理,调用该方法时默认返回null,执行null.getId()就触发了空指针异常。
另外你写的请求构造方式是正确的,MockMVC的multipart方法支持同时传递文件和普通参数。
修复后的测试代码
@ExtendWith(SpringExtension.class) @WebMvcTest(controllers = PhotoController.class) class PhotoControllerTest { @Autowired private MockMvc mockMvc; @MockBean private PhotoService photoService; @MockBean private PhotoRepository photoRepository; @Test public void whenPhotoAdded_thenVerifyStatus() throws Exception { // 构造测试文件 MockMultipartFile file = new MockMultipartFile( "image", "/Users/x/y/z/t.jpeg", MediaType.IMAGE_JPEG_VALUE, "image".getBytes() ); // 构造模拟返回的Photo对象,若实体类没有setId方法可直接用Mockito.mock构造 Photo mockPhoto = new Photo("test-title"); mockPhoto.setId("test-photo-id"); // 给Service方法打桩,指定对应参数下的返回值 Mockito.when(photoService.addPhoto(Mockito.eq("test-title"), Mockito.any(MultipartFile.class))) .thenReturn(mockPhoto); // 执行请求+断言 mockMvc.perform(multipart("/photos/add") .file(file) .param("title", "test-title")) .andExpect(status().is3xxRedirection()) // 接口返回redirect,对应状态码为302,不是200 .andExpect(redirectedUrl("/photos/test-photo-id")); // 可直接断言跳转路径是否符合预期 // 可选:验证Service方法被正确调用了一次,参数符合预期 Mockito.verify(photoService, Mockito.times(1)) .addPhoto(Mockito.eq("test-title"), Mockito.any(MultipartFile.class)); } }
Multipart接口单元测试最佳实践
- 参数传递确认:文件参数名要和Controller的
@RequestParam指定的名称完全一致,普通字符串参数用.param()方法传递即可,完全符合表单提交逻辑 - Mock依赖打桩:所有被Mock的Service层方法,都要根据测试场景预设返回值,避免空指针异常
- 断言覆盖全面:除了状态码,还可以覆盖返回路径、Mock方法调用次数、入参正确性等维度的校验
- 边界场景测试:可以补充空文件、超大文件、非法文件类型、title为空等异常场景的测试,验证接口容错性
内容的提问来源于stack exchange,提问作者bc_msa
相关产品推荐
相关产品推荐

