2008/03/13からのアクセス回数 16283
Spring 2.0から導入されたsession scopeオブジェクトは、DispatcherServletで処理されるため MockHttpServletRequestを使った単体テストでは、bean定義ファイルでscope="session"で 定義されたsession scopeオブジェクトのsession単位での持ち回りのテストができません。
session scopeオブジェクトのテストには、
GenericWebApplicationContextをcreateApplicationContextメソッドで返すTestCaseとして AbstractTransactionalSpringWebContextTestsを追加しました。
AbstractTransactionalSpringWebContextTestsのcreateApplicationContextは以下の通りです。
protected ConfigurableApplicationContext createApplicationContext(final String[] locations) { GenericWebApplicationContext context = new GenericWebApplicationContext( new GenericApplicationContext().getDefaultListableBeanFactory()); context.setServletContext(new MockServletContext()); customizeBeanFactory(context.getDefaultListableBeanFactory()); createBeanDefinitionReader(context).loadBeanDefinitions(locations); context.refresh(); // StaticWebApplicationContext のpostProcessBeanFactoryと同じ処理を追加 ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope()); beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope(false)); beanFactory.registerScope(WebApplicationContext.SCOPE_GLOBAL_SESSION, new SessionScope(true)); return context; }
HTTPリクエストの前後にRequestContextFilterと同様の処理行うメソッド、beginRequest, endRequestメソッドをAbstractTransactionalSpringWebContextTestsに定義しました。
beginRequestメソッドは、
public void beginRequest(MockHttpServletRequest req) { ServletRequestAttributes attributes = new ServletRequestAttributes(req); req.setAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE, attributes); RequestContextHolder.setRequestAttributes(attributes); ServletContext sc = req.getSession().getServletContext(); GenericWebApplicationContext wac = (GenericWebApplicationContext)getApplicationContext(); wac.setServletContext(sc); sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, (GenericWebApplicationContext)getApplicationContext()); }
endRequestメソッドは、
public void endRequest(MockHttpServletRequest req) { ServletRequestAttributes attributes = (ServletRequestAttributes) req .getAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE); ServletRequestAttributes threadAttributes = (ServletRequestAttributes) RequestContextHolder .getRequestAttributes(); if (threadAttributes != null) { // We're assumably within the original request thread... if (attributes == null) { attributes = threadAttributes; } RequestContextHolder.setRequestAttributes(null); LocaleContextHolder.setLocale(null); } if (attributes != null) { attributes.requestCompleted(); if (logger.isDebugEnabled()) { logger.debug("Cleared thread-bound request context: " + req); } } }
と定義しました。
session scopeオブジェクトのテストメソッドを定義するには、
以下にMemberOpsControllerを例にHTTP要求の前後処理の仕方を示します。
MemberOpsController memberOpsController = (MemberOpsController)getApplicationContext().getBean("memberOpsController"); ModelAndView mv = null; beginRequest(req); mv = memberOpsController.handleRequest(req,new MockHttpServletResponse()); endRequest(req);
同一セッションは、つぎのようにして持ち回ることができます。
HttpSession session = req.getSession(); req = new MockHttpServletRequest("POST","memberops/list.htm"); req.setSession(session);
これで、session scopeオブジェクトの単体テストができるようになります。
このページが分かりづらいとのご指摘が多いので、TestCase例で説明します。
を参考にしながら、以下の説明を見てください。
AbstractTransactionalSpringWebContextTestsのサブクラスとして定義します。
public class TestCase extends AbstractTransactionalSpringWebContextTests {
次にSessionを後のリクエストに継承するメソッドを示します。
のは、SpringではフィルタRequestContextFilterの処理と同じこと処理を実現するためです。 例では、handleRequestの前後に挿入してあります。
try { beginRequest(req); mv = memberOpsController.handleRequest(req,new MockHttpServletResponse()); endRequest(req); } catch (Exception err) { err.printStackTrace(); }
は、新しく生成したMockHttpServletRequestに前回の要求のsessionをセットすることで再現します。
HttpSession session = req.getSession(); req = new MockHttpServletRequest("POST","memberops/list.htm"); // sessionを次の要求に引き継ぐ req.setSession(session);
念のために、testmemberOpsController_Listのメソッドを示します。
// memberOpsController list method test public void testmemberOpsController_List() { dbUnitHelperDao.restore("src/test/resources/dump.xml"); MockHttpServletRequest req = new MockHttpServletRequest("POST","memberops/list.htm"); MemberOpsController memberOpsController = (MemberOpsController)getApplicationContext().getBean("memberOpsController"); ModelAndView mv = null; try { beginRequest(req); mv = memberOpsController.handleRequest(req,new MockHttpServletResponse()); endRequest(req); } catch (Exception err) { err.printStackTrace(); } Member expectedMember = (Member)getApplicationContext().getBean("expectedMember"); assertNull(mv.getViewName()); Member[] members = (Member[])mv.getModel().get("memberList"); assertEquals(memberManager.print(expectedMember), memberManager.print(members[0])); HttpSession session = req.getSession(); req = new MockHttpServletRequest("POST","memberops/list.htm"); // sessionを次の要求に引き継ぐ req.setSession(session); memberOpsController = (MemberOpsController)getApplicationContext().getBean("memberOpsController"); mv = null; try { beginRequest(req); mv = memberOpsController.handleRequest(req,new MockHttpServletResponse()); endRequest(req); } catch (Exception err) { err.printStackTrace(); } expectedMember = (Member)getApplicationContext().getBean("expectedMember"); assertNull(mv.getViewName()); members = (Member[])mv.getModel().get("memberList"); assertEquals(memberManager.print(expectedMember), memberManager.print(members[0])); }
この記事は、
皆様のご意見、ご希望をお待ちしております。