2013-09-12 4 views
0

Я работаю над написанием теста junit для моего весеннего приложения. Ниже мой тест junit, который вызывает метод afterPropertiesSet моего класса InitializeFramework, который реализует интерфейс InitializingBean.ScheduledExecutorService не работает во время моего теста junit

Ниже поток, где мой JUnit тест вызывает afterPropertiesSet метод, а затем этот метод будет вызывать initializeModel метод в одном классе, а затем этот метод имеет планировщик, который будет вызывать getBundlesInfo методы каждые несколько минут. Но почему-то во время моего junit метод getBundlesInfo вообще не называется.

@Test 
public void testFramework() { 


    try { 
     InitializeFramework io = new InitializeFramework(); 
     io.afterPropertiesSet(); 

    } catch (Exception e) { 

    } 
} 


public class InitializeFramework implements InitializingBean { 

private static long checkWithDBInterval = 1L; 

private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); 

    @Override 
    public void afterPropertiesSet() throws Exception { 

     try { 

     // other code here 

     initializeModel(); 
     } catch (Exception e) { 

     } 
    } 

    private void initializeModel() { 

     final ScheduledFuture<?> taskHandle = scheduler.scheduleAtFixedRate(
       new Runnable() { 
        public void run() { 
         try { 
          getBundlesInfo(); 
         } catch(Exception ex) { 
          // log exception here 
         } 
        } 
       }, 0, checkWithDBInterval, TimeUnit.MINUTES); 
    } 


    // this method is not getting called from my junit test 
    protected static void getBundlesInfo() { 

    // some code here 
    // have put the breakpoint here.. 

    } 
} 

Может ли кто-нибудь помочь мне в этом? Что я тут делаю? но во время моего приложения запуска, этот поток работает прекрасно и getBundlesInfo вызывается ... Только в JUnit он не работает ..

+0

Я бы предположил, что код зависит от некоторых других ресурсов, которые не работают. У вас должен быть метод, который инициализирует все необходимые ресурсы. Используйте его вместе с аннотацией '@ BeforeClass'. – mike

ответ

0

Вы заметите, что если вы измените свой getBundlesInfo() на что-то вроде

protected static void getBundlesInfo() { 
     System.out.println("ay"); 
    } 

и TimeUnit вы используете TimeUnit.MILLISECONDS, чтобы он печатал как можно больше. Например, я получил

ay 
ay 
ay 
ay 

Это потому, что JUnit очищает все потоки, запущенные на JVM, перед выходом. Он убивает/останавливает/прерывает их.

+0

Я вижу ... Не могли бы вы немного рассказать об этом утверждении: «Это потому, что JUnit очищает все потоки, запущенные на JVM, перед выходом». Итак, что я должен делать в моем случае, чтобы заставить эту работу работать? – AKIWEB

+0

@ TrekkieTechieT-T В зависимости от того, что вы хотите, вы можете заставить ваш '@ Test' спать/ждать сообщения из потока кода. Это не особенно чисто для единичного испытания. –

+0

В моем случае я пытаюсь сделать вызов метода getBundlesInfo, вызвав метод afterPropertiesSet. Я не где мне спать/ждать в моем @Test, а также, как получить какое-то уведомление из потока кода? Есть предположения? – AKIWEB

2

Это происходит из-за того, что ваш юнит-тест завершается до того, как планировщик выполнит вашу Runnable.

Вы хотите проверить, что afterPropertiesSet звонки getBundlesInfo или вы хотите проверить повторное обращение getBundlesInfo?

Как ваш модуль проверяет, что getBundlesInfo получил вызов? Или ты еще не там?

Если вы просто хотите увидеть, что getBundlesInfo называется, вы либо могли бы сделать прямой вызов к нему и увеличить initialDelay вашего планировщика checkWithDBInterval или заглушки getBundlesInfo с Mockito и/или Powermock, чтобы, например, использовать CountDownLatch для синхронизировать.

Ну или просто подождите пару секунд после звонка до afterPropertiesSet, а затем проверьте, был ли вызван getBundlesInfo (что вы можете сделать с Mockito также по отношению к BAT).

В любом случае, вы можете добавить код, который вызывает остановку на службе исполнителя после окончания теста


Поскольку вы используете Spring:
Рассмотрят с помощью прилагаемых Task Execution and Scheduling рамки для планирования повторного вызова до getBundlesInfo и после того, как afterPropertiesSet напрямую вызовет getBundlesInfo.

Как бы то ни было, вот пример с обрезанием и использованием CountDownLatch для ожидающей части. Мне также пришлось сделать getBundlesInfo нестационарным, так как я не мог быстро запомнить/найти, как заглушить статический метод.

import static org.mockito.Mockito.*; 
import java.util.concurrent.*; 

import org.junit.Test; 
import org.mockito.invocation.InvocationOnMock; 
import org.mockito.stubbing.Answer; 

public class StackOverflowTest 
{ 

    public static class ClassWithScheduler 
    { 
     private static long checkWithDBInterval = 1L; 
     private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); 

     public void entryPoint() 
     { 
      scheduler.scheduleAtFixedRate(new Runnable() { 
       public void run() 
       { 
        try 
        { 
         thisHasToBeCalled(); 
        } 
        catch(Exception ex) 
        { 
         // log exception here 
        } 
       } 
      }, 0, checkWithDBInterval, TimeUnit.MINUTES); 

     } 

     protected void thisHasToBeCalled() 
     { 
      System.out.println("thisHasToBeCalled was called"); 
     } 
    } 

    // since we are waiting on another thread either use a timed-wait (latch.await also 
    // has a variant which accepts a timeout) or use the timeout attribute of the 
    // @Test annotation 
    @Test(timeout = 5000L) 
    public void testCall() throws Exception 
    { 
     // create latch which this thread waits on and the scheduler thread 
     // notifies on 
     final CountDownLatch latch = new CountDownLatch(1); 

     // create instance 
     ClassWithScheduler instance = spy(new ClassWithScheduler()); 

     // stub thisHasToBeCalled to notify on the latch 
     doAnswer(new Answer<Void>() { 
      @Override 
      public Void answer(InvocationOnMock invocation) throws Throwable 
      { 
       // call the real method 
       invocation.callRealMethod(); 

       // notify waiting thread 
       latch.countDown(); 

       System.out.println("stub"); 

       return null; 
      } 
     }).when(instance).thisHasToBeCalled(); 

     // execute 
     instance.entryPoint(); 

     // wait for thread to call the stubbed method 
     latch.await(); 

     // assert that the method was called/
     verify(instance).thisHasToBeCalled(); 
    } 
} 
Смежные вопросы