测试涉及ScheduledExecutorService#scheduleAtFixedRate的代码时单元测试失败

问题描述 投票:0回答:1

就可重现的例子而言,我有以下课程

public class SampleCaching {

    ScheduledExecutorService executorService;
    @com.google.inject.Inject InterestCache interestCache;
    @Inject MultimediaCache multimediaCache;

    @Inject
    public SampleCaching(InterestCache interestCache, MultimediaCache multimediaCache) {
        this.executorService = Executors.newScheduledThreadPool(3);
        this.interestCache = interestCache;
        this.multimediaCache = multimediaCache;
    }

    protected void calculate() {
        interestCache.populateOne();
        interestCache.populateTwo();
        multimediaCache.populateMultimedia();
        log.info("Cache population completed!");
    }

    public void start() {
        executorService.scheduleAtFixedRate(this::calculate, 
                                0, 20, TimeUnit.MINUTES); // notice initial delay 
    }
}

而且似乎事实是我为此代码编写了一个半错误的单元测试,其内容为:

@org.junit.runner.RunWith(PowerMockRunner.class)
@org.powermock.core.classloader.annotations.PowerMockIgnore("javax.management.*")
public class SampleCachingTest {

    @org.mockito.Mock InterestCache interestCache;
    @Mock MultimediaCache multimediaCache;
    @org.mockito.InjectMocks SampleCaching sampleCaching;

    @Test
    public void testInvokingStart() throws Exception {
        sampleCaching.start();
        verify(multimediaCache, times(0)).populateMultimedia();
        verify(interestCache, times(0)).populateOne();
        verify(interestCache, times(0)).populateTwo();
    }
}

[[我说,是半不正确的,因为如果我增加实际代码中的初始延迟来举例说明1 MINUTE,则该测试通过。真正让我问这个问题的是,如果我将测试更改为

@Test public void testInvokingStart() throws Exception { sampleCaching.start(); verify(interestCache, times(1)).populateOne(); verify(interestCache, times(1)).populateTwo(); }

它总是成功执行,但为多媒体添加verify却总是使测试失败:

verify(multimediaCache, times(1)).populateMultimedia(); // or even to `times(0)`

这种行为(确定性或确定性)背后有原因吗?修复此测试的正确方法是什么?

就可复制的示例而言,我有以下公共类SampleCaching {ScheduledExecutorService executorService; @ com.google.inject.Inject InterestCache interestCache; ...
java unit-testing junit mockito scheduledexecutorservice
1个回答
0
投票
因此,您要自己触发方法SampleCaching#start,这又告诉ScheduledExecutorService以0秒的初始延迟调用calculate方法。这将在单独的线程中发生。同时,您的测试代码将继续运行,并且接下来要做的就是验证您的多媒体缓存上没有调用populateMultimedia方法。然后对populateOne和populateTwo相同。此操作的成功取决于在另一个启动线程中的calculate方法所取得的进展。如果已经调用了populateMultimedia方法,则您的第一个验证将失败,其他验证也会失败。另一方面,如果尚未进行得那么远,则测试将成功,但可能在populateOne或populateTwo上失败。
© www.soinside.com 2019 - 2024. All rights reserved.