I'm trying to test the start method of an Activity that uses RequestFactory.
I manage to test RF calls invoking directly the service using this article example, but I'm missing something mocking RF calls called from the tested activity.
It's more clear with the code.
EDIT : more specific
What I really want to know, is how to replace the response of a Receiver method (onSuccess,onFailure...) called in an Activity? This way I would be able to test the code inside the receiver method.
So basically here is my activity :
public class MyActivity extends AbstractActivity implements MyView.Presenter {
private List<MyEntityProxy> entities;
private MyView view;
private ClientFactory cf;
private EntityRequest entityRequest;
private AppRequestFactory rf;
@Inject
public ClientsListActivity(ClientsListViewEditor view, ClientFactory clientFactory) {
this.view = view;
this.clientFactory = clientFactory;
rf = clientFactory.getRequestFactory();
}
@Override
public void start(final AcceptsOneWidget panel, EventBus eventBus) {
view.setPresenter(this);
refreshEntities();
}
public void refreshEntities(){
entityRequest = rf.entityRequest();
entityRequest.getAll().with("opt1,"opt2").fire(new Receiver<List<MyEntityProxy>>() {
@Override
public void onSuccess(List<MyEntityProxy> response) {
entities = response;
entityRequest = requestFactory.clientRequest();
}
});
}
public List<MyEntityProxy> getEntities(){
return entities;
}
}
To test it in JUnit I use GwtMockito, so here is the test class MyActivityTest :
@RunWith(GwtMockitoTestRunner.class)
public class ClientListActivityTest{
private MyActivity activity;
private EventBus eventBus;
private AppRequestFactory rf;
@GwtMock
private ClientFactory cf;
@GwtMock
private MyView;
@GwtMock
private AcceptsOneWidget panel;
@Before
public void setUp(){
eventBus = new SimpleEventBus();
rf = RequestFactoryHelper.create(AppRequestFactory.class);
cf = new ClientFactory(eventBus,rf);
activity = new MyActivity(view,cf);
}
@Test
public void testStartActivity(){
List<EntityProxy> result = new ArrayList<EntityProxy>();
EntityProxy expectedClient = mock(EntityProxy.class);
expectedEntity.setNom("Client 1");
EntityProxy expectedClient2 = mock(EntityProxy.class);
expectedEntity.setNom("Client 2");
result.add(expectedEntity);
result.add(expectedEntity2);
//Here I have to change the requestFactory Call, so I try that but without success :
Request<?> req = mock(Request.class);
doReturn(req).when(mock(MyEntityRequest.class)).getAll();
doAnswer(RequestFactoryHelper.ok(result)).when(req).fire(any(Receiver.class));
activity.start(panel, eventBus);
assertEquals(activity.getEntities().size(),2); //This Test fails size = 0
}
}
My RequestFactoryHelper (inspired from here ) :
public class RequestFactoryHelper {
private static class MockServiceLocator implements ServiceLocator {
private final Map<Class<?>, Object> services = new HashMap<Class<?>, Object>();
@Override
public Object getInstance( Class<?> clazz ) {
// Make sure to return always the same mocked instance for each requested type
Object result = services.get( clazz );
if (result == null) {
result = mock( clazz );
services.put( clazz, result );
}
return result;
}
}
private static class MockServiceDecorator extends ServiceLayerDecorator {
@Override
public <T extends ServiceLocator> T createServiceLocator( Class<T> clazz ) {
return (T) serviceLocator;
}
}
private static MockServiceLocator serviceLocator = new MockServiceLocator();
private static ServiceLayer serviceLayer = ServiceLayer.create( new MockServiceDecorator() );
/**
* Creates a {@link RequestFactory}.
*/
public static <T extends RequestFactory> T create( Class<T> requestFactoryClass ) {
SimpleRequestProcessor processor = new SimpleRequestProcessor( serviceLayer );
T factory = RequestFactorySource.create( requestFactoryClass );
factory.initialize( new SimpleEventBus(), new InProcessRequestTransport( processor ) );
return factory;
}
/**
* Returns the same service instance as used by the RequestFactory internals.
*/
public static <T> T getService( Class<T> serviceClass ) {
T result = (T) serviceLocator.getInstance( serviceClass );
reset( result ); // reset mock to avoid side effects when used in multiple tests
return result;
}
/**
* Returns the value passed to {@link Receiver#onSuccess(Object)}
*/
public static <T> T captureResult( Receiver<T> receiver ) {
ArgumentCaptor<Object> captor = ArgumentCaptor.forClass( Object.class );
verify( receiver ).onSuccess( (T) captor.capture() );
return (T) captor.getValue();
}
public static <T> Answer<T> ok(final T result) {
return new Answer<T>() {
@Override
public T answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
Object _receiver = args[args.length - 1];
Receiver<T> receiver = (Receiver<T>)_receiver;
receiver.onSuccess(result);
return null;
}
};
}
}
Receiver<List<MyEntityProxy>> rec = mock(Receiver.class);then I calldoAnswer(RequestFactoryHelper.ok(result)).when(req).fire(any(Receiver.class));and I can catch the result usingList<MyEntityProxy> result = RequestFactoryHelper.captureResult(receiver);But doing that I'm not testing the code inside my activity. - Pintouch