如何在单元测试中使用gwteventbinder和guice

时间:2014-03-07 13:06:12

标签: java unit-testing gwt guice

我在普通Java中使用Guice for DI而不是GIN(在正常执行中使用)执行GWT应用程序的单元测试。我还使用GWTEventBinder库(https://github.com/google/gwteventbinder)作为事件声明和监听的支持库。

根据库的要求,我为每个听取事件的类声明了一个EventBinder。在正常执行期间,绑定器的实例由GIN注入。

然而,在单元测试期间,实例应由Guice生成。关于如何让Guice生成EventBinder实例的任何想法?

1 个答案:

答案 0 :(得分:1)

根据issue对gwteventbinder项目(您报告:)的评论和建议,我已经提出以下代码:

public class FakeEventBinderProvider implements FakeProvider<EventBinder<?>> {
    @Override
    public EventBinder<?> getFake(Class<?> type) {
        return (EventBinder<?>) Proxy.newProxyInstance(FakeEventBinderProvider.class.getClassLoader(), new Class<?>[] { type }, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, final Object[] args) throws Throwable {
                String methodName = method.getName();
                assert methodName.equals("bindEventHandlers");

                final List<HandlerRegistration> registrations = new LinkedList<HandlerRegistration>();
                EventBus eventBus = (EventBus) args[1];

                List<Method> presenterMethods = getAllMethods(args[0].getClass());
                for (final Method presenterMethod : presenterMethods) {
                    if (presenterMethod.isAnnotationPresent(EventHandler.class)) {
                        @SuppressWarnings("unchecked") // Should always be ok, since the Generator for EventBinder should do all the safe-checking 
                        Class<? extends GenericEvent> eventType = (Class<? extends GenericEvent>) (presenterMethod.getParameterTypes())[0];
                        registrations.add(eventBus.addHandler(GenericEventType.getTypeOf(eventType), new GenericEventHandler() {
                            @Override
                            public void handleEvent(GenericEvent event) {
                                try {
                                    presenterMethod.setAccessible(true);
                                    presenterMethod.invoke(args[0], event);
                                } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                                    throw new RuntimeException(e);
                                }
                            }
                        }));
                    }
                }

                return new HandlerRegistration() {
                    @Override
                    public void removeHandler() {
                        for (HandlerRegistration registration : registrations) {
                            registration.removeHandler();
                        }
                        registrations.clear();
                    }
                };
            }
        });
    }

    private List<Method> getAllMethods(Class<?> type) {
        List<Method> methods = new LinkedList<Method>();
        methods.addAll(Arrays.asList(type.getDeclaredMethods()));
        if (type.getSuperclass() != null) {
            methods.addAll(getAllMethods(type.getSuperclass()));
        }
        return methods;
    }
}

根据建议,我已根据FakeUiBinderProvider的实施情况进行了此操作。 一旦你摆脱了Java Reflection cruft,它就非常简单了:

  1. 找到使用@EventHandler注释的所有方法。
  2. 注册一个新的处理程序,该处理程序调用指定事件类型的回调方法。
  3. 返回一个HandlerRegistration,调用removeHandler时会删除上一点中添加的所有处理程序(此行为是从gwteventbinder的实际实现中复制而来的)。
  4. 请记住注册此提供商,例如在@Before方法中注册:

    @Before
    public void setUpEventBindery() {
        GwtMockito.useProviderForType(EventBinder.class, new FakeEventBinderProvider());
    }
    

    您只需要为基本界面EventBinder执行此操作,因为GwtMockito.useProviderForType的文档说:

      

    (..)给定的提供者应该用于GWT.create给定类型的实例和它的子类