2014-03-07 2 views
3

GIN 대신 DI에 대해 Guice를 직접 사용하여 일반 Java로 GWT 어플리케이션의 단위 테스트를 실행합니다 (일반 실행에서 사용됨). 또한 이벤트 선언 및 수신을 지원하는 라이브러리로 GWTEventBinder 라이브러리 (https://github.com/google/gwteventbinder)를 사용하고 있습니다.유닛 테스트 중에 guice와 gwteventbinder를 사용하는 방법

라이브러리에서 필요에 따라 이벤트를 수신하는 각 클래스에 대해 EventBinder를 선언합니다. 정상적인 실행 중에는 바인더의 인스턴스가 GIN에 의해 ​​주입됩니다.

그러나 단위 테스트 중에 Guice가 인스턴스를 생성해야합니다. Guice가 EventBinder 인스턴스를 생성하는 방법에 대한 아이디어가 있습니까? gwteventbinder 프로젝트에 issue의 의견과 제안 (당신이 :)보고있는)을 기반으로

답변

1

, 나는 다음과 같은 코드로 왔어요 :

제안으로
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의 구현에. 당신은 자바 반사 cruft에 제거하면 그것은 매우 간단합니다 :

  1. @EventHandler 주석 모든 방법을 찾습니다.
  2. 지정된 이벤트 유형에 대한 콜백 메소드를 호출하는 새 처리기를 등록하십시오.
  3. removeHandler을 호출하면 이전 지점에서 추가 된 모든 처리기가 제거됩니다 (이 동작은 gwteventbinder의 실제 구현에서 복사 됨).

당신의 @Before 방법, 예를 들어,이 공급자를 등록하는 것을 잊지 마십시오 :

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

을 당신은 이후 GwtMockito.useProviderForType에 대한 설명서로, 기본 인터페이스, EventBinder 위해이 작업을 수행 할 필요가 말한다 :

(..) 주어진 공급자는 주어진 유형의 인스턴스를 GWT.create하는 데 사용해야하며 하위 클래스을 생성해야합니다.

관련 문제