#freeze [[Spring-MVC/ステップ・バイ・ステップ]] 2008/03/23からのアクセス回数 &counter; #contents プログラムのデバッグできるようになりましたので、次はmavenを使ってプログラムのテストが できるようにしましょう。 Springの提供するテストには、 - 単体テスト - 結合テスト - トランザクションテスト があります。 ここでは、JunitとMockHttpServletRequestの使い方について説明します。 ** テストの準備 [#u12fe24a] *** ディレクトリの追加 [#sdcbbc65] mavenのWebアプリケーションにテストケースを組み込む場合には、以下のディレクトリを追加します。 #pre{{ + mvc-convention/ |- pom.xml |-+ src/ |-+ main/ | |-+ resources/ | |-+ webapp/ | |-+ WEB-INF/ | |- web.xml | |- index.jsp |-+ test/ |-+java/ ← 追加 |-+resources/ ← 追加 }} - src/test/java/ には、テストケースのjavaプログラムを配置 - src/test/resources/ には、テスト用のリソースファイルを配置 を追加します。 *** ライブラリの追加 [#gd0b07de] 次に、テストに使用するSpringのライブラリをpom.xmlに追加します。 テストには、spring-testが必要です。[[MVNRepository>http://mvnrepository.com/]]で検索すると、 #pre{{ <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>2.5.2</version> </dependency> }} をpom.xmlに追加します。 *** クラスパスの変更 [#iff2d857] 以下のコマンドを実行して.project, .classpathファイルを更新します。 #pre{{ $ rm .project .classpath $ mvn eclipse:eclipse -DdownloadSources=true }} ** テストケースの作成 [#ac895904] 準備ができましたので、テストケースを作成しましょう。 Springでは、 - AbstractDependencyInjectionSpringContextTests - AbstractTransactionalSpringContextTests - AbstractTransactionalDataSourceSpringContextTests のテストケースを提供しています。今回はトランザクションのテストが可能なAbstractDependencyInjectionSpringContextTestsを使用することにします。 *** クラスの単体テスト [#z4c124fd] 最初にStubRecipeManagerのfindByIdの単体テスト作ってみましょう。 src/test/java以下にSampleTestCase.java として以下のファイルを作成します。 #pre{{ import org.springframework.showcase.coverc.domain.Recipe; import org.springframework.showcase.coverc.service.StubRecipeManager; import org.springframework.test.AbstractDependencyInjectionSpringContextTests; public class SampleTestCase extends AbstractDependencyInjectionSpringContextTests { public void testFindById() { StubRecipeManager manager = new StubRecipeManager(); Recipe recipe = manager.findById(1L); assertNotNull(recipe); assertEquals("Goats Cheese with beetroot sauce", recipe.getName()); } } }} JUnitでは、個々のテストは、''public void testXXXX()'のように定義しなければなりません。 testFindByIdでの処理は以下の通りです。 - StubRecipeManagerのインスタンスmanagerを作成する - managerにfindByIdメソッドでIdが1のrecipeを取り出す。 - recipeがNullでなく、nameが"Goats Cheese with beetroot sauce"であることを確認する *** 単体テストの実行 [#h2de5ac9] テストケースができたので、実際にJunitを使った単体テストをしましょう。 mavenでは、単体テストを簡単に実行するために、''test''というゴールを提供しています。 コマンドラインから以下のコマンドを入力すると、自動的にSmapleTestCase.javaをコンパイル、テストを実行します。 #pre{{ $ mvn test Listening for transport dt_socket at address: 8000 [INFO] Scanning for projects... [INFO] ------------------------------------------------------------------------ [INFO] Building mvc-convention Maven Webapp [INFO] task-segment: [test] [INFO] ------------------------------------------------------------------------ -- 途中省略 ------------------------------------------------------- T E S T S ------------------------------------------------------- Running SampleTestCase 2008/03/23 16:47:00 org.springframework.test.AbstractDependencyInjectionSpringContextTests prepareTestInstance 情報: ApplicationContext has not been configured for test [SampleTestCase]: dependency injection will NOT be performed. Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.458 sec Results : Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 }} テストで1つの情報(Macでは???と文字化けします)がでます。 - SpringのBean定義が設定されていない旨の警告 テストの結果は、Results:以下の #pre{{ Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 }} で確認します。 1個のテストを実行し、失敗、エラー、スキップがすべて無いことが確認できます。 もちろん、Eclipseを使って単体テストを実行することも可能です。 - Runメニューから"Run..."を選択する - RunダイアログのJUnitを選択し、右クリックでNewを選択する - RunダイアログのRunボタンを押す とJUnitが実行します。 ** Mockオブジェクトを使った結合テスト [#yb48f909] 次に、SpringのBean定義ファイルを使った結合テストの方法について説明します。 *** リソースのコピー [#j8ca0af0] 最初にBean定義ファイルをテスト用リソースファイルにコピーします。 - src/test/resources/にWEB-INFディレクトリを追加します - src/main/webapp/WEB-INF以下のapplicationContext.xml, coverc-servlet.xmlを src/test/resources/WEB-INFにコピーします coverc-servlet.xmlのSwitchBoardContrllerの定義に以下のようにidを追加してください。 #pre{{ <bean id="switchBoadController" class="org.springframework.showcase.coverc.web.SwitchBoardController" parent="baseRecipeController"/> }} *** テストケースでのBean定義ファイル設定方法 [#l3e8c69b] テストケースで使用するSpringのBean定義ファイルは、getConfigLocationsメソッドで定義 する約束になっています。 getConfigLocationsは以下のように定義します。 #pre{{ public String[] getConfigLocations() { return new String[] { "WEB-INF/applicationContext.xml", "WEB-INF/coverc-servlet.xml" }; } }} *** テストメソッドの追加 [#l054839d] Mockオブジェクトを使った結合テストの例を以下に示します。 - MockHttpServletRequestを使ってMockのHTTPServletRequestを生成します - SpringのBean定義に従って生成されたApplicationContextからswitchBoadControllerを取り出します - switchBoadControllerにHTTPServletRequestを処理(handleRequest)させます - hadleRequestで返されたModelAndViewのviewNameがnullであることを確認します - ModelAndViewのmodelからrecipeListを取り出します。 - recipeListのサイズが3であることを確認します - 最初のRecipeのNameが”Goats Cheese with beetroot sauce”であることを確認します #pre{{ public void testIntegrated() throws Exception { MockHttpServletRequest req = new MockHttpServletRequest("POST","switchBoadController/listRecipes.htm"); SwitchBoardController controller = (SwitchBoardController)getApplicationContext().getBean("switchBoadController"); ModelAndView mv = controller.handleRequest(req,new MockHttpServletResponse()); assertNull(mv.getViewName()); List list = (List)mv.getModel().get("recipeList"); assertEquals(3, list.size()); Recipe recipe = (Recipe)list.get(0); assertEquals("Goats Cheese with beetroot sauce", recipe.getName()); } }} *** 結合テストの実行 [#he6d6a2c] Bean定義ファイルを追加し、Mockオブジェクトを使った結合テストを実行すると以下のように 出力されます。 #pre{{ $ mvn test -- 途中省略 ------------------------------------------------------- T E S T S ------------------------------------------------------- Running SampleTestCase 2008/03/23 18:28:31 org.springframework.test.AbstractSingleSpringContextTests -- 途中省略 Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.623 sec Results : Tests run: 2, Failures: 0, Errors: 0, Skipped: 0 }} 2個のテストメソッドが正常に動作していることが確認できました。 #ref(SampleTestCase.java); ** コメント [#o04e4088] この記事は、 #vote(おもしろかった[6],そうでもない[2],わかりずらい[10]) #vote(おもしろかった[7],そうでもない[3],わかりずらい[11]) 皆様のご意見、ご希望をお待ちしております。 #comment_kcaptcha