如何为调用流式Restful API的consume函数编写JUnit测试?
为流式API消费函数编写JUnit测试方案
核心思路
用Spring提供的MockRestServiceServer模拟RestTemplate的流式响应,既能真实触发execute方法的内部回调逻辑,解决你之前测试中execute调用被跳过的问题,又能验证Consumer<StreamingDataBatch>是否正确处理每一批数据。
测试步骤与代码示例
1. 依赖准备
确保测试依赖包含spring-test(Spring Boot项目可直接使用spring-boot-starter-test,已内置该依赖)。
2. 测试类实现
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.test.web.client.MockRestServiceServer; import org.springframework.web.client.RestTemplate; import static org.springframework.test.web.client.match.MockRestRequestMatchers.*; import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; import static org.junit.jupiter.api.Assertions.*; import java.util.ArrayList; import java.util.List; // 替换成你的服务类实际名称 class StreamingServiceTest { private StreamingService service; private RestTemplate restTemplate; private MockRestServiceServer mockServer; @BeforeEach void setUp() { restTemplate = new RestTemplate(); mockServer = MockRestServiceServer.createServer(restTemplate); // 假设你的服务类通过构造注入RestTemplate和batchSize参数 service = new StreamingService(restTemplate, 10); } @Test void consume_shouldProcessAllStreamingBatchesCorrectly() throws Exception { // 1. 构造模拟的流式JSON数组响应 String mockStreamingJson = """ [ {"id": 1, "data": "batch1"}, {"id": 2, "data": "batch2"}, {"id": 3, "data": "batch3"} ] """; // 2. 配置MockServer,匹配请求规则并返回模拟响应 mockServer.expect(requestTo("/api/stream-data")) .andExpect(method(HttpMethod.POST)) .andExpect(header("Authorization", "test-jwt-token")) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andRespond(withSuccess(mockStreamingJson, MediaType.APPLICATION_JSON)); // 3. 用List捕获Consumer处理的所有批次数据 List<StreamingDataBatch> processedBatches = new ArrayList<>(); // 4. 调用被测试的consume方法 service.consume("/api/stream-data", "test-jwt-token", processedBatches::add); // 5. 验证结果 mockServer.verify(); // 验证请求是否符合预期 assertEquals(3, processedBatches.size()); assertEquals(1, processedBatches.get(0).getId()); assertEquals("batch2", processedBatches.get(1).getData()); } @Test void consume_shouldThrowExceptionWhenResponseIsNotArray() throws Exception { // 构造非数组格式的错误响应 String invalidJson = "{\"code\": 400, \"msg\": \"invalid format\"}"; mockServer.expect(requestTo("/api/stream-data")) .andRespond(withSuccess(invalidJson, MediaType.APPLICATION_JSON)); // 验证是否抛出预期异常 IllegalStateException exception = assertThrows(IllegalStateException.class, () -> { service.consume("/api/stream-data", "test-jwt-token", batch -> {}); }); assertEquals("The response is not a JSON array.", exception.getMessage()); mockServer.verify(); } }
关键说明
- MockRestServiceServer的作用:它会拦截RestTemplate的所有请求,真实执行
execute方法内的请求回调和响应处理逻辑,彻底解决你之前测试中execute调用被跳过的问题。 - 流式响应模拟:直接构造JSON数组字符串作为响应内容,MockServer会自动将其封装为输入流返回,
processStream方法会像处理真实流式响应一样逐行解析。 - 验证逻辑:通过List捕获Consumer的调用记录,可直接验证每一批数据的解析结果;同时验证请求头、请求方法、请求体等是否符合业务预期。
额外提示
processStream是私有方法,无需单独测试,通过测试public的consume方法即可完全覆盖其逻辑。若确需单独测试,可将其改为包访问权限(不推荐),或通过反射调用(仅作为兜底方案)。
内容的提问来源于stack exchange,提问作者ADS
相关产品推荐
相关产品推荐

