Spring MockMVC中MockMultipartFile的getInputStream存根失败求助
解决MockMultipartFile输入流存根匹配失败的问题
问题根源
- 实例不匹配:
MockMultipartFile的getInputStream()每次调用都会返回新的ByteArrayInputStream实例,你存根时用的是第一次调用的实例,而控制器调用服务时生成的是全新实例,导致参数匹配失败,返回默认的null。 - 匹配器使用错误:你把
ArgumentMatchers.any(InputStream.class)赋值给变量的写法违反了Mockito规则,匹配器必须直接在when()的参数列表中调用,不能提前赋值。
正确解决方案
方案1:使用通用匹配器+精确参数包装
Mockito要求:如果方法参数中使用了任意一个匹配器,所有参数都必须用匹配器包装。因此需要用eq()来包裹确定的值,同时用any()匹配输入流:
final Integer value1 = 2023; final Boolean value2 = Boolean.TRUE; final MockMultipartFile file = new MockMultipartFile( "file", "file.csv", MediaType.TEXT_PLAIN_VALUE, "Hello, World!".getBytes() ); // 正确写法:所有参数都用匹配器包装 when(inputService.validateInput(eq(value1), eq(value2), any(InputStream.class))) .thenReturn(ValidationResult.builder().build()); mockMvc.perform(multipart("/file/validate") .file(file) .param("value1", value1.toString()) .param("value2", value2.toString()) ) .andDo(print()).andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON));
方案2:自定义匹配器校验输入流内容
如果需要更精准的匹配(确保输入流内容和文件一致),可以自定义ArgumentMatcher来校验输入流的字节内容:
import org.mockito.ArgumentMatcher; import java.io.InputStream; import java.io.IOException; import java.util.Arrays; // 自定义输入流内容匹配器 class InputStreamContentMatcher implements ArgumentMatcher<InputStream> { private final byte[] expectedBytes; public InputStreamContentMatcher(byte[] expectedBytes) { this.expectedBytes = expectedBytes; } @Override public boolean matches(InputStream inputStream) { try { byte[] actualBytes = inputStream.readAllBytes(); return Arrays.equals(expectedBytes, actualBytes); } catch (IOException e) { return false; } } }
存根时使用这个匹配器:
when(inputService.validateInput( eq(value1), eq(value2), argThat(new InputStreamContentMatcher(file.getBytes())) )) .thenReturn(ValidationResult.builder().build());
这种方式可以确保只有内容和目标文件一致的输入流才会触发存根的返回值,比通用匹配器更严谨。
内容的提问来源于stack exchange,提问作者DJViking
相关产品推荐
相关产品推荐

