【发布时间】:2014-12-04 06:24:43
【问题描述】:
我正在尝试测试使用 RequestFactory 的 Activity 的启动方法。
我设法使用this article example 测试直接调用服务的 RF 调用,但我缺少从测试活动调用的模拟 RF 调用的东西。
用代码更清楚。
编辑:更具体
我真正想知道的是,如何替换 Activity 中调用的 Receiver 方法(onSuccess,onFailure...)的响应?这样我就可以测试接收器方法中的代码了。
所以基本上这是我的活动:
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;
}
}
为了在 JUnit 中测试它,我使用 GwtMockito,所以这里是测试类 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
}
}
我的 RequestFactoryHelper(灵感来自 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;
}
};
}
}
【问题讨论】:
-
您能更具体地说明您遇到的问题吗?
-
我将编辑我的问题以指定。在我的测试中,我想测试 refresh() 方法,该方法用于通过 RF 调用从服务器获取实体。所以我需要替换Receiver的onSuccess()方法中的响应。之后,我将能够根据我在测试中的响应替换来测试 onSuccess 方法中的代码。是不是更清楚了? :s
-
顺便说一句,好问题。我走的路线与您尝试模拟 requestfactory 方法相同,但无济于事。如果我理解您的问题,则返回模拟结果的 ok 方法。我想出了另一种在我的情况下效果很好的解决方案。我要么使用 AsyncDataProvider 类,要么使用命令模式,在其中我可以轻松地模拟来自命令的响应。这也可以为您提供一个简单的缓存挂钩。我知道这并不能解决您的问题,但这是一个很好的解决方法,并带来了一些额外的好处。 Ray Ryan 有一段视频解释了 google 如何使用命令模式
-
了解最佳实践。 youtube.com/watch?v=PDuhR18-EdM
-
如果我在测试方法中创建接收器,ok 方法有效:
Receiver<List<MyEntityProxy>> rec = mock(Receiver.class);然后我调用doAnswer(RequestFactoryHelper.ok(result)).when(req).fire(any(Receiver.class));,我可以使用List<MyEntityProxy> result = RequestFactoryHelper.captureResult(receiver);捕获结果但是这样做我不是在测试我的活动中的代码。
标签: unit-testing gwt junit mockito requestfactory