So I've been asked at work to add a JUnit test to my code (our app didn't have testing) but I've hit my head against the wall. Essentially I need to test MyDataSourceImpl.Java
public class MyDataSourceImpl implements MyDataSource {
@Autowired
PropertieService propertieService;
public HttpResponse execute(String url){
MyHttpClient myClient = new MyHttpClient(url,propertieService.getProperties());
HttpResponse response = myClient.performCall();
this.someOtherStuff(response);
return response;
}
}
this is how I run my Test:
@RunWith(MockitoJUnitRunner.class)
public class MyDataSourceImplTest {
@InjectMocks
private MyDataSourceImpl myDataSourceImpl;
@Mock
private PropertieService propertieService;
@Test
public void simpleCall(){
when(propertieService.getProperties()).thenReturn(new HashMap<String,String>());
HttpResponse response = myDataSourceImpl.execute("https://nothing.com");
assertEquals(response,"");
}
}
Now, I can mock the propertieService just fine, but how do I mock the myClient.performCall()? because that tries to call a database and it's never going to work in a Test. I tried treating MyHttpClient like PropertieService and add a @Mock and a when thenReturn, that did nothing. is there any way to do this?
edit: when I write that "I tried treating MyHttpCliente like PropertieService" I mean that I added a @Mock private MyHttpClient myClient; to my Test, and added a line like when(myClient.performCall()).thenReturn(new HttpResponse()); to my simpleCall(). and that does nothing, it still tries to execute the real performCall() method.
Mocking of constructors may be possible, but it's a sign that your code isn't structured in the best way possible.
Imagine if it was:
public class MyDataSourceImpl implements MyDataSource {
@Autowired
MyHttpClient myClient;
public HttpResponse execute(String url) {
HttpResponse response = myClient.performCall(url);
this.someOtherStuff(response);
return response;
}
}
One fewer dependencies, and easy to mock. All from moving the url
to the performCall
method.
Create a level of indirection:
public interface HttpClientCall {
HttpResponse performCall(String url)
}
public final class MyHttpClientCallAdaptor implements HttpClientCall {
private final PropertieService propertieService;
MyHttpClientCallAdaptor(PropertieService propertieService) {
this.propertieService = propertieService;
}
@Override
public HttpResponse performCall(String url) {
return new MyClient(url, propertieService)
}
}
Now depend on HttpClientCall
:
public class MyDataSourceImpl implements MyDataSource {
@Autowired
HttpClientCall myClient;
public HttpResponse execute(String url) {
HttpResponse response = myClient.performCall(url);
this.someOtherStuff(response);
return response;
}
}