Reputation: 619
I've the problem that I like to test some values that are hidden by another method in my junit test. How would you to things like that. With Mockito? Subclassing?
Here the problem:
public class MyService extends AbstractService {
public ResponseObject insert(SomeData data) {
Request request = createRequest(data);
Response response = new Response();
callService(request, response);
return createResponseObject(response);
}
protected void callBackendService(...) {
...
}
}
How would you test the values that are passed to the
callBackendService()method?
Is there a more elegant way than use subclassing?
MyService service = new MyService() {
@Override
protected void callBackendService(...) {
assertEquals(...);
...
}
}
Regards,
Mike
Upvotes: 3
Views: 124
Reputation: 15909
One school of thought is that you should only Unit Test your public classes. Therefore just do your assertions on the ResponseObject
that is returned from insert()
.
Otherwise, using a mocking framework like Mockito you can factor out the callBackendService() method into it's own class (e.g. ServiceCaller
). Then you can create a mock ServiceCaller object and verfiy the parameters that are passed to it.
Something like this...
public class ServiceCaller {
public callBackendService(Request request, Response response) {
...
}
}
Then your class should look something like this...
public class MyService extends AbstractService {
private ServiceCaller serviceCaller;
public ResponseObject insert(SomeData data) {
Request request = createRequest(data);
Response response = new Response();
serviceCaller.callBackendService(request, response);
return createResponseObject(response);
}
public setServiceCaller(ServiceCaller caller) {
this.serviceCaller = caller;
}
}
And finally a Mockito test is somthing like this...
@Test
public void testInsert() throws Exception {
// object to test
MyService ms = new MyService();
// test input values
Request req = new Request();
Response resp = new Response();
// create a mock class and inject it into your test class
ServiceCaller sc = mock(ServiceCaller.class);
ms.setServiceCaller = sc;
// execute the method under test
ms.insert(req, resp);
// now you can see if your mock was called with the expected params
verify(sc).callBackendService(req, resp);
}
I have omitted good design using Interfaces etc for brevity, but you'll get the idea.
Upvotes: 2
Reputation: 6580
NOTE: I'm assuming callService()
should be callBackendService()
Within one of your own classes, focus more on testing behavior rather than interactions between that class's methods. Testing behavior (as opposed to what you're trying to do) will keep your tests from being tightly coupled with your implementation. So for example, if you proceed with trying to test the callBackendService()
method and later change that implementation detail of your class, you'll break your test(s). If instead you focus on testing the behavior of the insert()
method, you can modify that specific call anytime you want and your test will only break if you've actually broken the desired behavior.
Furthermore, let's take a look at your insert method in more detail. If you tested the behavior of the createRequest()
method and new Response()
constructor in other tests, you already know those are producing exactly what you expect. So, creating a separate test that verifies the callBackendService()
method received the parameters you expect in this case really isn't testing anything new.
What you should do is test the outcome of invoking the insert()
method.
So the answer to your question is, don't test arguments to the callBackendService()
method.
Upvotes: 1
Reputation: 116
Don't test callBackendService() if it is just an implementation detail. If it is so complex, that it deserves it's own testing, refactor it into a seperate class.
Upvotes: 1