我正在为我的spring应用程序编写一些junit测试。下面是我的junit测试,该测试调用实现InitializingBean接口的afterPropertiesSet
类的InitializeFramework
方法。
下面是我的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期间不起作用。
最佳答案
发生这种情况是因为在计划程序执行Runnable之前退出了单元测试。
您是否要测试afterPropertiesSet
调用getBundlesInfo
还是要测试getBundlesInfo
的重复调用?
您的单元测试如何断言getBundlesInfo被调用?还是您不在那里?
如果只想看到getBundlesInfo
被调用,则可以直接调用它,并将调度程序的initialDelay
增加到checkWithDBInterval
,或者将Mccito和/或Powermock存根到getBundlesInfo
。使用CountDownLatch进行同步。
好吧,或者只是在调用afterPropertiesSet
之后等待几秒钟,然后检查是否调用了getBundlesInfo
(您也可以使用Mockito进行此操作)。
无论如何,您可能想要添加在测试完成后调用执行程序服务关闭的代码
由于您使用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();
}
}