我正在为我的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();
    }
}

08-04 08:18