Reputation: 221
I have some method that sends a request and receive a response. I get the response in header, it's a String
.
My method:
@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;
}
}
I'm trying do assert this response in my test, but without success. My test:
@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);
}
...
}
I'm not able to create a expected
item to assert
my result
. I'm getting null
on my result
Upvotes: 1
Views: 2014
Reputation: 1131
There's not much benefit in mocking the framework calls in a case like this, although it could be possible. You end up mocking everything and duplicate almost all of the production code to match the usage.
Try using something like MockWebServer
instead:
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);
}
}
There's a small overhead of starting the MockWebServer
but your test doesn't have to try to replicate what HttpClient
really does.
Upvotes: 1
Reputation: 39978
Instead of mocking HttpRespone object calls i will recommend to create. HttpResponse
object with corresponding values
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;
}
};
Upvotes: 2