调度程序在单元测试中工作不正确
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");
}
}
我需要从 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");
}
}