【问题标题】:GWT Unit Testing with RequestFactory / Activities使用 RequestFactory / 活动进行 GWT 单元测试
【发布时间】: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&lt;List&lt;MyEntityProxy&gt;&gt; rec = mock(Receiver.class);然后我调用doAnswer(RequestFactoryHelper.ok(result)).when(req).fire(any(Receiver.class));,我可以使用List&lt;MyEntityProxy&gt; result = RequestFactoryHelper.captureResult(receiver); 捕获结果但是这样做我不是在测试我的活动中的代码。

标签: unit-testing gwt junit mockito requestfactory


【解决方案1】:

这就是我测试接收器方法“onSuccess”的方式。我为 Mockito.doAnswer 创建了一个自定义答案。

要测试的代码。

public void myMethod(String arg1, String arg2) {
    requestFactory.adminRequest().someMethod(arg1, arg2).fire(new Receiver<Void>() {
        @Override
        public void onSuccess(Void response) {
            placeController.goTo(new MyPlace());
        }
    });
}

测试。

@Test
public void testMyMethod() {
    String arg1 = "arg1";
    String arg2 = "arg2";
    when(requestFactory.adminRequest()).thenReturn(adminRequest);
    when(adminRequest.someMethod(arg1, arg2)).thenReturn(request);
    doAnswer(new Answer<Void>() {

        @Override
        public Void answer(InvocationOnMock invocation) throws Throwable {
            Object[] args = invocation.getArguments();
            Receiver<Void> receiver = (Receiver<Void>) args[0];
            receiver.onSuccess(null);
            return null;
        }
    }).when(request).fire(any(Receiver.class));

    myActivity.myMethod(arg1, arg2);
    verify(adminRequest).someMethod(arg1, arg2);
    verify(request).fire(any(Receiver.class));
    verify(placeController).goTo(any(myPlace.class));

}

requestFactory、adminRequest、request 和 placeController 都是 mocks。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-29
    • 1970-01-01
    相关资源
    最近更新 更多