调度程序在单元测试中工作不正确

Scheduler works incorrect in unit testing

我需要从 public API 收集数据。我想每天或一天两次收集它。

public class AlphavantageStockRequestDispatcher {
    public static void startAlphavantageStockScraper(int timeInterval) {
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

        Runnable getStockList =
                new Runnable() {
                    @Override
                    public void run() {
                        List<AlphavantageStock> stocks = AlphavantageStockRequest.getStockPrices(); //Method contains requests

                        StockDao<AlphavantageStock> dao = new JpaAlphavantageStockDao();

                        for (AlphavantageStock stock : stocks) {
                            dao.save(stock);
                        }
                    }
                };

        scheduler.scheduleAtFixedRate(getStockList, 0, timeInterval, TimeUnit.HOURS);
    }
}

问题是当我从同一个 class 启动它时(只是添加了 main 方法并调用 startAlphavantageStockScraper(1); 它工作正常。但是当我想通过 JUnit 测试它时它不起作用(测试class 在对称包名称中,但在 test 子文件夹中):

public class AlphavantageStockRequestDispatcherTest {
    @Test
    public void startDispatcher_TwoFullCycles_WithOneHourIntervalBetween() {
        AlphavantageStockRequestDispatcher.startAlphavantageStockScraper(1);
    }
}

调试时我发现在单元测试执行中程序到达 public void run() 行然后跳过它。所以没有错误。程序正确结束,但没有任何用处。

任何帮助将不胜感激。

这就是异步编程的工作原理。在 AlphavantageStockRequestDispatcher class 你刚刚提交了一个任务,但你必须等待它完成。有几种方法可以处理这种情况。我更喜欢使用 java.util.concurrent.CountDownLatch 的状态通知。因此,在 AlphavantageStockRequestDispatcher class 中建议进行一些重构,如下所示:


public class AlphavantageStockRequestDispatcher {
    public static void startAlphavantageStockScraper(int timeInterval, CountDownLatch latch) {
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

        Runnable getStockList =
                new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("worker started");
                        try {
                            Thread.sleep(10_000L);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        } finally {
                            System.out.println("worker finished");
                            Optional.ofNullable(latch).ifPresent(CountDownLatch::countDown);
                        }
                    }
                };

        scheduler.scheduleAtFixedRate(getStockList, 0, timeInterval, TimeUnit.HOURS);

    }

}

现在可以测试了。

public class AlphavantageStockRequestDispatcherTest {

    @Test
    void startDispatcher_TwoFullCycles_WithOneHourIntervalBetween() throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(1);
        AlphavantageStockRequestDispatcher.startAlphavantageStockScraper(1, latch);
        latch.await(20, TimeUnit.SECONDS);
        System.out.println("first finished - need some assertions");
    }

}