I'm writing a Unit Test for a Class (CustomHttpClient) that internally uses a library (java.net.http.HttpClient) to make an external HTTP call.
Being it a Unit Test, I would mock the internal HttpClient call (using a mocking framework like Mockito) returning a mocked response.
The Class to test has been designed to initialize the client library (that I want to mock) internally:
public class CustomHttpClient
public HttpResonse doCall() {
// Build Http Client
HttpClient client = HttpClient.newBuilder().build();
// Build request
HttpRequest request = HttpRequest.newBuilder()
.uri("http://myserviceuri")
.GET()
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
// Do HTTP call --> TO MOCK WHEN UNIT TESTING
return client.send(request,HttpResponse.BodyHandlers.ofString());
}
}
For the way the class is designed, it is impossible to "replace" the HttpClient real instance with a mocked one during tests. Looking at the TDD, the used design effectively seems to break the principle that states that a class should be designed to be easily testable.
TDD suggests using Dependency injection to inject dependencies so that it can be easy to inject mocks when testing
According to this TDD principle, I see two different approaches:
- Passing the external library in the CustomHttpClient constructor
- Creating a Setter method to inject the external library
public class CustomHttpClient
private HttpClient client;
// External library injected on object creation
public CustomHttpClient(HttpClient client){
this.client = client;
}
public HttpResonse doCall() {
// Build request
HttpRequest request = HttpRequest.newBuilder()
.uri("http://myserviceuri")
.GET()
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
// Do HTTP call --> TO MOCK WHEN UNIT TESTING
return client.send(request,HttpResponse.BodyHandlers.ofString());
}
}
Anyway, both approaches seem to me to break the Single Responsibility principles and, at least, to be not elegant.
Why a CustomHttpClient consumer should have the responsibility of injecting a dependency that could be internally handled by the module itself? Is it acceptable for testing purposes?
Maybe I'm missing something and I really would appreciate any help :-)
P.S.: I also know that exists some Testing frameworks, like Powermocks, that are able to handle this particular use case, anyway I'm more interested in the correct design to use and why.
Thank you