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

如何为调用流式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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 15:50:38