ひよっこ。

I want to…

SpringFramework3 Controllerのhandlingのテスト

Posted by hikaruworld : 2010 12月 7

Spring3でMVCの@Controllerのテストを行いたい場合のやり方に関してメモしておきます。

Spring3においてControllerのテストを行う場合、
メソッド単位であれば単純にControllerをnewしてテストを行うことが出来ます。
つまり、以下のようなControllerがあった場合、

@Controller
@RequestMapping(value="/employee")
public class HomeController {

	/** とりあえずのサービス。必要に応じてMockなりStubなりを作る */
	private CommonService commonService;

	private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
	
	/** コンストラクタインジェクションでServiceを設定 */
	@Autowired(required=true)
	public HomeController(CommonService commonService) {
		this.commonService = commonService;
	}

	/**
	 * /employeeへのGETアクセスの場合に実行されるメソッド
	 */
	@RequestMapping(method=RequestMethod.GET)
	public String home() {
		this.commonService.login();
		
		return "home";
	}
	/**
	 * /employeeへのPOSTアクセスの場合に実行されるメソッド
	 */
	@RequestMapping(method=RequestMethod.POST)
	public String school() {
		return "school";
	}
}

テストは以下のように行います

@Test
public void testInner() {
	HomeController controller = new HomeController();
	String path = controller.home();
	assertThat(path, is("home"));
}

メソッドレベルの検証は上記のように非常に簡単になっているのですが、
HTTPレベルからのテストを考えると、DispatcherServletを経由したテストを行いたい場合があります。
ようするに、DispatcherServletを実行した場合に対象のControllerが起動し、適切なメソッドなりreturnなりが実行されるかの検証です。

このテストを行う場合は、ApplicationContextを@Injectした上で、
applicationContextが持っているhandler情報から、Controller情報を引くようにする必要があるようです。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({
	// contextConfigLocationの読み込み
	"file:src/main/webapp/WEB-INF/spring/root-context.xml",
	// DispatcherServletの読み込み
	"file:src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml"
})
public class HomeControllerTest {

	@Inject
	private ApplicationContext applicationContext;
	
	/** 検証したいController */
	private HomeController controller;
	
	/** 各種Mock */
	private MockHttpServletRequest request;
	private MockHttpServletResponse response;
	private HandlerAdapter handlerAdapter;
	
	private CommonService commonService;
	
	@Before
	public void setup() {
		this.request = new MockHttpServletRequest();
		this.response = new MockHttpServletResponse();

//		Map<String, HandlerAdapter> map =
//				applicationContext.getBeansOfType(HandlerAdapter.class);
		this.handlerAdapter =
				applicationContext.getBean(AnnotationMethodHandlerAdapter.class);
		this.commonService = applicationContext.getBean(CommonService.class);

		this.controller = applicationContext.getBean(HomeController.class);
		
//		this.controller = new HomeController(this.commonService);
	}
	/** Handlingの実処理 */
	private ModelAndView handle() throws Exception {
		// Map<String, HandlerMapping> map =
		//		applicationContext.getBeansOfType(HandlerMapping.class);
		// AnnotationによってHandlerMappingされた情報を取得
		HandlerMapping handlerMapping =
				this.applicationContext.getBean(DefaultAnnotationHandlerMapping.class);
		// RequestにマッチするControllerをMapping情報から取得
		// この内部にHomeControllerが含まれる。
		HandlerExecutionChain chain = handlerMapping.getHandler(this.request);

		// AOPの取得? TODO ???
		for (HandlerInterceptor interceptor : chain.getInterceptors()) {
			boolean bool = interceptor.preHandle(this.request, this.response, chain);
			if (!bool) {
				return null;
			}
		}
		// Controllerの実行を行い、結果を取得する
		return handlerAdapter.handle(this.request, this.response, chain.getHandler());
	}
	
	@Test
	public void testA() throws Exception {
		// 遷移すべきURLとHTTPメソッドを取得
		this.request.setRequestURI("/employee");
		this.request.setMethod("GET");

		// Controllerの呼び出し
		ModelAndView modelAndView = this.handle();

		// 検証処理
		assertViewName(modelAndView, "home");
	}
}

applicationContextから取得出来る、HandlerAdapterやHandlerMappingを
どれをとればよいかわからず、ちょっとはまりました。

以下、参考にしたblog。感謝。
* More on integration testing of Spring’s MVC annotation mapppings for controllers

Spring1.Xの知識がほとんどなので、便利になったもんですなというのが率直な感想です。
Controllerレベルのテストもメソッド単位でとても実行しやすくなってますね。

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

 
%d人のブロガーが「いいね」をつけました。