2012-02-21 8 views
1

Springバッチを呼び出すSpring MVCコントローラをテストするJUnitテストを実行すると、次の例外が発生します。ジョブ。ジョブには2つのタスクレットが含まれています。最初にファイル&からDBに書き込んでDBを更新します。どちらのタスクレットも同じDBを使用します。私が見る限り、例外はデータソースが閉じられていると私に伝えますが、DBでは最初のタスクレットが実行されているのに対し、2番目のタスクレットは実行されていません。Springバッチジョブを呼び出すControllerをユニットテストするときに "SQLException:データソースが閉じられています"

2番目のタスクレット(DBへの更新)中にデータソースが閉じられている(???)の理由を教えてください。

ブラウザからコントローラを呼び出すと、ジョブは両方のタスクレットを実行します。

ERROR [taskExecutor-1] (AbstractJob.java:306) - Encountered fatal error executing job 
org.springframework.batch.core.JobExecutionException: Flow execution ended unexpectedly 
    at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:141) 
    at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:281) 
    at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:120) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) 
    at java.lang.Thread.run(Thread.java:662) 
Caused by: org.springframework.batch.core.job.flow.FlowExecutionException: Ended flow=writeProductsJob at state=writeProductsJob.readWrite with exception 
    at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:152) 
    at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:124) 
    at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:135) 
    ... 5 more 
Caused by: org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for transaction; nested exception is java.sql.SQLException: Data source is closed 
    at org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:240) 
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:371) 
    at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:335) 
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:105) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202) 
    at $Proxy27.getStepExecutionCount(Unknown Source) 
    at org.springframework.batch.core.job.SimpleStepHandler.shouldStart(SimpleStepHandler.java:210) 
    at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:117) 
    at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:61) 
    at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:60) 
    at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:144) 
    ... 7 more 
Caused by: java.sql.SQLException: Data source is closed 
    at org.apache.commons.dbcp.BasicDataSource.createDataSource(BasicDataSource.java:1362) 
    at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044) 
    at org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:202) 
    ... 18 more 
Exception in thread "taskExecutor-1" org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for transaction; nested exception is java.sql.SQLException: Data source is closed 
    at org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:240) 
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:371) 
    at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:335) 
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:105) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202) 
    at $Proxy27.update(Unknown Source) 
    at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:329) 
    at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:120) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) 
    at java.lang.Thread.run(Thread.java:662) 
Caused by: java.sql.SQLException: Data source is closed 
    at org.apache.commons.dbcp.BasicDataSource.createDataSource(BasicDataSource.java:1362) 
    at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044) 
    at org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:202) 
    ... 11 more 
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 3.628 sec 

UPDATE:

テストクラス:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = {"classpath:applicationContext-test.xml"}) 
public class UploadFileValidatorTest { 

    @Autowired 
    private ApplicationContext applicationContext; 

    private MockMultipartHttpServletRequest request; 
    private MockHttpServletResponse response; 

    @Autowired 
    private MyController controller; 

    private MessageSource messageSource; 

    @Before 
    public void setUp() { 
     request = new MockMultipartHttpServletRequest(); 
     response = new MockHttpServletResponse(); 
    } 

    @Test 
    @DirtiesContext 
    public void testDoSomething() throws Exception { 

     DiskFileItem fileItem = null; 

     final File TEST_FILE = applicationContext.getResource("classpath:csv_example.txt").getFile(); 

     try 
     { 
      fileItem = (DiskFileItem) new DiskFileItemFactory().createItem("fileData", "text/plain", true, TEST_FILE.getName()); 
      InputStream input = new FileInputStream(TEST_FILE); 
      OutputStream os = fileItem.getOutputStream(); 
      int ret = input.read(); 
      while (ret != -1) 
      { 
       os.write(ret); 
       ret = input.read(); 
      } 
      os.flush(); 
      System.out.println("diskFileItem.getString() = " + fileItem.getString()); 
     } 
     catch (Exception e) 
     { 
      e.printStackTrace(); 
     } 

     ///////////////////////////////////////////////////////////////////// 

     request.addFile(multipartFile); 

     request.addParameter("email", "[email protected]"); 

     request.setRequestURI("/book/upload.html"); 

     final ModelAndView mav = new AnnotationMethodHandlerAdapter().handle(request, response, controller); 

     BindingResult bindException = (BindingResult) mav.getModel().get(BindingResult.MODEL_KEY_PREFIX + "uploadFile"); 
     for (Object object : bindException.getAllErrors()) { 
      if(object instanceof FieldError) { 
       FieldError fieldError = (FieldError) object; 

       assertEquals(fieldError.getField(), "fileData"); 

       System.out.println(messageSource.getMessage((FieldError) object, null)); 
      } 
     } 

    } 

} 

バッチ設定:

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
    <property name="dataSource" ref="dataSource" /> 
</bean> 

<bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean"> 
    <property name="transactionManager" ref="transactionManager" /> 
</bean> 

<bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher"> 
    <property name="jobRepository" ref="jobRepository" /> 
    <property name="taskExecutor" ref="taskExecutor"/> 
</bean> 

<bean id="taskExecutor" 
    class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"> 
    <property name="corePoolSize" value="5" /> 
    <property name="maxPoolSize" value="5" /> 
</bean> 

UPDATE 2:

私はtestDoSomething()試験方法の最後に次のコードを追加しようとしました:今、全体のジョブが実行され

ThreadGroup threadGroup = Thread.currentThread().getThreadGroup(); 

int activeCount = threadGroup.activeCount(); 

Thread[] list = new Thread[activeCount]; 

threadGroup.enumerate(list); 

for (Thread thread : list) { 
    if (thread.getName().startsWith("taskExecutor")) { 
     System.out.println("WAITING FOR THREAD: " + thread.getName()); 
     try { 
      thread.join(); 
     } 
     catch (InterruptedException ignore) {} 
    } 
} 

が、testDoSomething()は決して終わらない、それは死ぬことtaskExecutorスレッドの永遠に待つように思えます。 taskExecutorが決して死なない理由は何ですか?

+0

:2つのランチャーを定義する 例。そのメソッドにブレークポイントを設定し、誰がそれを呼び出す責任があるのか​​確認できますか?私はそれが 'ApplicationContext.close()'であると確信しています...また、統合テストはどのように見えますか?あなたはSpringのコンテキストをどうやって始めますか? –

+0

私の元の投稿の下部にある**更新**をご覧ください。 – rapt

+0

@ Tomasz Nurkiewicz - あなたが見ることができるように、ジョブはコントローラのスレッド(およびjunitテスト)とは別のスレッドで実行するように定義されています。したがって、コントローラスレッドが終了すると、junitはすべてのオープンリソース(オープンデータソースなど)を閉じます。ジョブスレッドが終了するまで、junitにリソースのクローズを待つように指示するにはどうすればよいですか? – rapt

答えて

0

私のテストでも同様の問題があります。

バッチジョブがを非同期に起動し、とテストが終了しましたが、ジョブが実行中(または実行しようとしています)です。コンテキストはすでに閉じられています(DataSourceを含むすべてのBeanも閉じられています)。したがって、テストで同期JobLauhcherを使用する必要があります。私は `main`スレッドが既に` BasicDataSource.closeを() `を呼び出す、アプリケーション・コンテキストを停止している間に、このタスクレットが別のスレッドで実行されることだけを推測することができます

<beans:bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">  
     <beans:property name="jobRepository" ref="jobRepository"/> 
    </beans:bean> 

    <beans:bean id="jobLauncher_asynch" 
      class="org.springframework.batch.core.launch.support.SimpleJobLauncher"> 
     <beans:property name="jobRepository" ref="jobRepository" /> 
     <beans:property name="taskExecutor" ref="taskExecutor"/> 
    </beans:bean> 
関連する問題