如何为单元测试创​​建 header 响应?

How can I create a header response for unit tests?

我有一些发送请求和接收响应的方法。我在 header 中收到响应,它是 String.

我的方法:

@Override
    public String myMethod(SomeClass someItem) {
        try {

            HttpRequest request = HttpRequest.newBuilder()
                    .POST(HttpRequest.BodyPublishers.ofString(myBodyString))
                    .uri(getUri())
                    .header(OAUTH, getToken())
                    .headers(KEY_HEADER, valueHeader)
                    .headers(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
                    .build();

            var response = httpClient.send(request, HttpBodyHandlers.ofCodec());

            if (response.statusCode() == HttpStatus.OK.value()) {
                return response.headers().allValues(LOCATION).get(0);
            } else {
                log.warn(ERROR_LOG + response.statusCode());
                return null;
            }
        } catch (Exception e) {
            log.error(ERROR_LOG + e.getCause());
            return null;
        }
    }

我正在尝试在我的测试中断言此响应,但没有成功。 我的测试:

@ExtendWith(MockitoExtension.class)
class ClassToTest {

    private final static String URL = "https://myUrl/";
    private final static String ACCESS_TOKEN = "access_token";

    private final Clock clock = Clock.fixed(Instant.now(), ZoneId.of("UTC"));

    private ClassToTest service;

    @Mock
    private HttpClient httpClient;

    @Mock
    private OAuth oAuthClient;

    @Mock
    private HttpResponse httpResponse;

    @BeforeEach
    void setUp() {
        service = new ClassToTest(httpClient, oAuthClient);
        when(config.getValue(SERVICE_URL)).thenReturn(AVISO_URL);
        when(oAuthClient.getToken()()).thenReturn(ACCESS_TOKEN);
    }

    @Test
    void myMethod_toTest_success() throws IOException, InterruptedException {
        when(httpClient.send(any(HttpRequest.class), any(HttpResponse.BodyHandler.class))).thenReturn(httpResponse);
        when(httpResponse.statusCode()).thenReturn(HttpStatus.OK.value());

        var result = service.myMethod(myItem);
        assertEquals("UUID", result);
    }
...
}

我无法为 assert 我的 result 创建 expected 项目。我的 result

得到了 null

我建议创建对象调用而不是模拟 HttpRespone 对象调用。 HttpResponse 具有相应值的对象

   HttpResponse<String> httpResponse = new HttpResponse<String>() {
        @Override
        public int statusCode() {
            return 200;
        }

        @Override
        public HttpRequest request() {
            return null;
        }

        @Override
        public Optional<HttpResponse<String>> previousResponse() {
            return Optional.empty();
        }

        @Override
        public HttpHeaders headers() {
            return HttpHeaders.of(Map.of("", List.of()), (v1,v2)->true);
        }

        @Override
        public String body() {
            return null;
        }

        @Override
        public Optional<SSLSession> sslSession() {
            return Optional.empty();
        }

        @Override
        public URI uri() {
            return null;
        }

        @Override
        public HttpClient.Version version() {
            return null;
        }
    };

在这种情况下模拟框架调用并没有多大好处,尽管这是可能的。您最终模拟了所有内容并复制了几乎所有的生产代码以匹配用法。

尝试使用类似 MockWebServer 的东西:

class ClassToTest {
    private MockWebServer mockWebServer;

    @BeforeEach
    void init() {
        this.mockWebServer = new MockWebServer();
    
        when(config.getValue(SERVICE_URL))
            .thenReturn(mockWebServer.url("/").toString());

        // ...
    }

    @Test
    void myMethod_toTest_success() {
        mockWebServer.enqueue(new MockResponse()
            .addHeader(LOCATION, "UUID")
            .setBody("some response")
            .setResponseCode(200));

        var result = service.myMethod(myItem);
        assertEquals("UUID", result);
    }
}

启动 MockWebServer 的开销很小,但您的测试不必尝试复制 HttpClient 的真正作用。