Reputation: 825
I have an application with following structure:
Client class:
class Client{
private Requests requests;
private Settings settings;
protected Client(Settings settings){
this.settings = settings;
this.requests = new Requests(settings);
}
public Requests getRequests(){
return requests;
}
}
Requests class:
class Requests{
private RequestsHandler requestsHandler;
private Settings settings;
protected Requests(Settings settings){
this.requestHandler = new RequestHandler();
this.settings = settings;
}
public Bicycles getBicycles(BicyclesParameters bicycleParams){
return requestsHandler.callService(bicycleParams, settings, "service/getBicycles", Bicycles.class)
}
}
And my
RequestsHandler class:
class RequestsHandler{
public BaseResponse callService(BaseParams params, Settings settings, String serviceURL, Class<? extends BaseResponse> responseType ) {
here I use RestTemplate to get data from external Service
}
}
In my Unit tests, I would like to mock the data from external service, so I did as following: create a mocking RequestsHandler object, mock the callService method and register this mock object with @Bean:
@Configuration
public class TestConfiguration {
@Bean
public RequestsHandler requestsHandler() {
RequestsHandler requestsHandler = Mockito.mock(RequestsHandler.class);
when(requestsHandler.callService(new BicyclesParameters(), new Settings(),
"/service/getBicyles", Bicycles.class))
.thenReturn(new Bicycles().setBicyclesList(new Bicycle[] {new Bicycle(), new Bicycle()}));
return requestsHandler;
}
}
and my test class:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestConfiguration.class)
public class TestGetBicycles{
@Test
public void testGetBicycles() {
Client = new Client(new Settings);
Bicycles bicycles = client.getRequests.getBicycles(new BicyclesParamters());
assertNotNull(bicycles.getBicyclesList());
}
}
But when I run the test, I had two problems:
org.mockito.exceptions.misusing.InvalidUseOfMatchersException
, I have no idea why but when I changed my mock object to:
when(requestsHandler.callService(any(), any(),
any(), any()))
.thenReturn(new Bicycles().setBicyclesList(new Bicycle[] {new Bicycle(), new Bicycle()}));
the error went away, but
Can anyone help me at these points? This is my first time working with Mockito so I am so confused now.
Thank you in advanced!
Upvotes: 2
Views: 5546
Reputation: 131526
You create a mock but this is never used in the scope of the executed method.
In fact your problem is that you want to mock an object that is created inside a object created during the invocation of the tested method :
protected Requests(Settings settings){
this.requestHandler = new RequestHandler(); // <- You want to mock this field
this.settings = settings;
}
It is not possible with plain mockito. In your case you have two ways :
1) refactor your code to provide an additional constructor that accepts the RequestHandler
as parameter. In your case Client
and Requests
could accept RequestHandler
.
For example for Client
:
protected Client(Settings settings, RequestsHandler requestHandler){
this.settings = settings;
this.requests = new Requests(settings, requestHandler);
}
and you test could look like :
@Mock
RequestsHandler requestsHandlerMock;
...
@Test
public void testGetBicycles() {
Client = new Client(new Settings(), requestsHandlerMock);
Bicycles bicycles = client.getRequests.getBicycles(new BicyclesParamters());
//...
}
2) Using libraries that relies on reflection and byte code generation (as CGLib) at runtime. PowerMock and PowerMockito are well known in Java for that.
Personally I favor the refactoring as it is possible. It makes the code always clearer and cleaner. In fact these libraries are not bad in themselves but it may create some technical debt as by using them too often you may be encouraged to cheat with the help of the library instead of improving the API of the code to test.
Upvotes: 3