daybreaksnow's diary

私を私と呼びたい

[GWT]RPCの自動テスト

公式
基本:http://www.gwtproject.org/doc/latest/tutorial/JUnit.html
非同期:http://www.gwtproject.org/doc/latest/DevGuideTesting.html#DevGuideAsynchronousTesting

シンプルなテスト

testパッケージにクラスを作って、GWTTestCaseを継承してgetModuleNameでgwt.xmlのパスを指定すればOK。

サンプルコード

public class StockWatcherTest extends GWTTestCase {

	@Override
	public String getModuleName() {
		//gwt.xmlの名前と合わせる
		return "com.google.gwt.sample.stockwatcher.StockWatcher";
	}

	public void testSimple(){
		assertTrue(true);
	}
}

典型的なエラー

モジュール名のタイプミス

getModuleNameで返す名前がgwt.xmlの配置、名前と一致していない場合。

Development Modeの出力

com.google.gwt.core.ext.UnableToCompleteException: (see previous log entries)
	at com.google.gwt.dev.cfg.ModuleDefLoader.nestedLoad(ModuleDefLoader.java:278)
	...
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

コンソールへの出力

   [ERROR] Unable to find 'com/google/gwt/sample/stockwatcher/StockWather.gwt.xml' on your classpath; could be a typo, or maybe you forgot to include a classpath entry for source?
Exception in thread "UnitCacheLoader" java.lang.RuntimeException: Unable to read from byte cache

パッケージの誤り

gwt.xmlでsource指定されていないパッケージにテストクラスがある場合に発生
デフォルトではclient,shareが指定されていたので、テストクラスをclientパッケージに入れた。

Development Modeの出力

com.google.gwt.junit.JUnitFatalLaunchException: The test class 'com.google.gwt.sample.stockwatcher.StockWatcherTest' was not found in module 'com.google.gwt.sample.stockwatcher.StockWatcher'; no compilation unit for that type was seen
	at com.google.gwt.junit.JUnitShell.checkTestClassInCurrentModule(JUnitShell.java:743)
	...
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

JUnit4を指定した場合。

クラスパスにJUnit3を指定したら動作した。
GWTTestCaseはJUnit4に対応していない?

Development Modeの出力

com.google.gwt.junit.JUnitFatalLaunchException: The test class 'com.google.gwt.sample.stockwatcher.client.StockWatcherTest' had compile errors; check log for details
	at com.google.gwt.junit.JUnitShell.checkTestClassInCurrentModule(JUnitShell.java:743)
	...
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

RPCのテスト

非同期実行の戻りを待つために、GWTTestCaseのdelayTestFinish、finishTestを使う。

サンプルコード

public void testServlet(){
	final GreetingServiceAsync greetingService = GWT
			.create(GreetingService.class);
	//60秒まではレスポンスを待つ(ブレークを張ってもよいように)
	delayTestFinish(60 * 1000);
	//NOTE:RequestURI=/com.google.gwt.sample.stockwatcher.StockWatcher.JUnit/greet
	greetingService.greetServer("hoge",
			new AsyncCallback<String>() {
		public void onFailure(Throwable caught) {
			fail();
		}
		public void onSuccess(String result) {
			//テスト終了を通知。本来はここでassertしてから呼ぶ
			finishTest();
		}
	});
}

また、RPCのテストを行う場合は、gwt.xmlに以下のようにマッピングを書く必要がある。
(ここがめちゃくちゃはまった)

<servlet path="/greet" class="com.google.gwt.sample.stockwatcher.server.GreetingServiceImpl" />

参考:対応するweb.xml(デフォルトで作成されたもの)

<servlet>
    <servlet-name>greetServlet</servlet-name>
    <servlet-class>com.google.gwt.sample.stockwatcher.server.GreetingServiceImpl</servlet-class>
  </servlet>
  
  <servlet-mapping>
    <servlet-name>greetServlet</servlet-name>
    <url-pattern>/stockwatcher/greet</url-pattern>
  </servlet-mapping>

マッピングが書かれていないと、RPCコール時に以下のレスポンスがonFailureに渡ってくる。

[WARN] 404 - POST /com.google.gwt.sample.stockwatcher.StockWatcher.JUnit/greet (xxx.yy.zzz.fff) 1445 bytes