Slim3 + GWT のユニットテストで mockito を使ってみる
Slim3 + GWT でクライアント側のテストをするために、Gin はちょっとオーバースペックな気がしたので mockito を使ってみてる。
private ItemServiceImpl itemService = spy(new ItemServiceImpl()); @Test public void myTest() throws Exception { ClientFactory clientFactory = mock(ClientFactory.class); when(clientFactory.getEventBus()).thenReturn(new SimpleEventBus()); Activity topActivity = mock(Activity.class); when(clientFactory.getTopActivity()).thenReturn(topActivity); when(clientFactory.getItemService()).thenReturn(itemServiceAsync); ... topActivity.getItems(); verify(itemService).getItems();
で、これのitemServiceAsyncなんだけども、これをどうやって作ろうかと。
コールバックのテストってどうやるんだろう?
最初はモックを使わずに new ItemServiceAsync(){ ... } とテストコードに書いていたんだけど、メソッドが増えたらいちいち書いてられない。
ちょっと迷った末にProxyを作ることにした。
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import com.google.gwt.user.client.rpc.AsyncCallback; public class AsyncServiceProxy { @SuppressWarnings("unchecked") public static <T1, T2> T1 getProxy(Class<T1> async, final T2 service) { return (T1) Proxy.newProxyInstance( AsyncServiceProxy.class.getClassLoader(), new Class[] {async}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Class<?>[] params = method.getParameterTypes(); Class<?>[] serviceParams = new Class<?>[params.length - 1]; for (int i = 0; i < params.length - 1; i++) { serviceParams[i] = params[i]; } Method serviceMethod = null; try { serviceMethod = service.getClass().getMethod(method.getName(), serviceParams); } catch (SecurityException e) { e.printStackTrace(); return null; } catch (NoSuchMethodException e) { e.printStackTrace(); return null; } Object[] serviceArgs = new Object[args.length - 1]; int i; for (i = 0; i < args.length - 1; i++) serviceArgs[i] = args[i]; AsyncCallback<Object> callback = (AsyncCallback<Object>) args[i]; Object ret = serviceMethod.invoke(service, serviceArgs); callback.onSuccess(ret); return null; } }); } }
やっつけ感満載のコードだけれども。
これで
ItemServiceAsync itemServiceAsync = AsyncServiceProxy.getProxy(ItemServiceAsync.class, itemService);
と書けば AsyncService => ServiceImpl => AsyncCallback#onSuccess と変換して呼び出すコールバックが生成できる。
なんだかmockitoや他のライブラリにちゃんとしたやり方がありそうな気がするが、見つからなかったのでとりあえずこれで。
mockito 参考:
http://d.hatena.ne.jp/Naotsugu/20101109/1289304795
http://d.hatena.ne.jp/takahashikzn/20101001/1285897862
http://tech.cm55.com/wiki/mockito/General