DeltaCap019 :
I am trying to create a test case for AlbumsController
which fetches data from the network and parses it.
AlbumService
: Responsible for network call and getting data. ( Assume it can be anything that performs some async task and gives callback accordingly so as to avoid "Server" specific mocking solutions )
public class AlbumsController {
public void getAlbums(final ServiceCallback<AlbumsWrapper> albumsServiceCallback) {
new AlbumsService().fetchAlbums(new ServiceCallback<NetworkResponse>() {
@Override
public void onSuccess(NetworkResponse response) {
// parse response
}
@Override
public void onFailure(NetworkResponse error) {
// do something for Failure
}
});
}
public class AlbumControllerTest {
@Mock
private ServiceCallback<NetworkResponse> serviceCallback;
@Captor
private ArgumentCaptor<ServiceCallback<AlbumsWrapper>> albumsWrapper;
@Captor
private ArgumentCaptor<ServiceCallback<NetworkResponse>> networkResponseArgumentCaptor;
@Before
public void init() {
MockitoAnnotations.initMocks(this);
}
@Test
public void parseAlbums_EmptyList_ReturnsTrue() {
// below are different ways I am trying with no success so far.
AlbumsController albumsController = new AlbumsController();
albumsController.getAlbums(albumsWrapper.capture());
NetworkResponse response = new NetworkResponse();
networkResponseArgumentCaptor.capture();
networkResponseArgumentCaptor.getValue().onSuccess(response);
}
}
Aim:
- To mock AlbumService inside
getAlbums
method so that instead of getting data from the server I should be able to callonSuccess()
with my test data as an argument. And is it possible to get the list after parsing so as that I canassert
base on the data in the list? - I don't want to move code responsible for parsing to some method and make that public. My intention here is to understand how to handle such a case.
- Open for refactoring of code if that's what is required to be taken care of in TDD.
- Full solution or pointers to look for both are appreciated.
Libraries
- mockito-core:2.2.9
- junit:4.12
Maciej Kowalski :
If small refactoring is the option then:
1) Move the new AlbumsService()
to a package level method:
AlbumService createAlbumService(){
return new AlbumService();
}
...
public void getAlbums(final ServiceCallback<AlbumsWrapper> albumsServiceCallback) {
createAlbumService().fetchAlbums(new ServiceCallback<NetworkResponse>()
package
visibility is enough as the test class will be in the same package as the AlbumController
.
2) Spy the AlbumController
:
@Spy
private AlbumsController albumsControllerSpy = new AlbumController();
@Mock
private AlbumService albumServiceMock;
3) Make the createAlbumService()
method return your mock:
@Test
public void parseAlbums_EmptyList_ReturnsTrue() {
doReturn(albumServiceMock).when(albumControllerSpy).createAlbumService();
...