[Spring] TestContext Framework で WebApplicationContext を使う
Direct Web Remoting (DWR) を Spring 統合含めて導入したら、これが WebApplicationContext でしか利用できないスコープを利用しているみたいで、ユニットテストで ApplicationContext の生成ができなくなってしまった。
この問題は認識されているようで JIRA に要求が上がっているのだが、対応されるのは Spring 3.0 ということで、いつになることやら。そこで、このチケットのコメントにも記載されている方法を参考に、現状の Spring 2.5 の TestContext Framework で WebApplicationContext を利用できるようにしてみた。
TestContext Framework では、@ContextConfiguration アノテーションで ApplicationContextLoader を指定できるので、まず WebApplicationContext を生成する独自の ApplicationContextLoader を作成する。
public class XmlWebApplicationContextLoader extends AbstractContextLoader { /** ロガー */ private static final Logger log = LoggerFactory.getLogger(XmlWebApplicationContextLoader.class); @Override protected String getResourceSuffix() { return "-context.xml"; } @Override public final ConfigurableApplicationContext loadContext(String... locations) throws Exception { if (log.isDebugEnabled()) { log.debug("Loading ApplicationContext for locations [" + StringUtils.arrayToCommaDelimitedString(locations) + "]."); } GenericWebApplicationContext context = new GenericWebApplicationContext(); context.setServletContext(new MockServletContext()); prepareContext(context); customizeBeanFactory(context.getDefaultListableBeanFactory()); createBeanDefinitionReader(context).loadBeanDefinitions(locations); AnnotationConfigUtils.registerAnnotationConfigProcessors(context); customizeContext(context); context.refresh(); context.registerShutdownHook(); return context; } /** * prepareContext * @param context */ protected void prepareContext(GenericApplicationContext context) {} /** * costomizeBeanFactory * @param beanFactory */ protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {} /** * createBeanDefinitionReader * @param context * @return BeanDefinitionReader */ protected BeanDefinitionReader createBeanDefinitionReader( final GenericApplicationContext context) { return new XmlBeanDefinitionReader(context); } /** * customizeContext * @param context */ protected void customizeContext(GenericApplicationContext context) {} }
ApplicationContext として GenericWebApplicationContext を利用し、そこに MockServletContext をインジェクトしている。それ以外は XmlWebApplicationContextLoader と同じ。
あとはテストの基底クラスで、この ApplicationContextLoader を使うように設定するだけ。
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"/applicationContext.xml"}, loader = XmlWebApplicationContextLoader.class) public abstract class AbstractTestCase { ....
データベースを使っているなら、さらにトランザクション関係の設定もアノテーションで記述しておく。
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true) @Transactional @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"/applicationContext.xml"}, loader = XmlWebApplicationContextLoader.class) public abstract class AbstractTransactionalTestCase { ....
これで、無事ユニットテストが動作するようになった(WebApplicationContext 固有のスコープがちゃんと機能しているかは確認していないが)。