Java 8 测试并发
Java 8 Testing Concurrency
所以...
我有这个实用程序 class 在初始调用在给定时间后未返回后执行重试(理论上是任何事情),并不断这样做直到任何源 returns 数据或者直到所有人都筋疲力尽。这使用 ExecutorCompletionService
的 .poll
方法来触发何时重试。请参阅以下实用程序代码 class...
final RetrySources[] retrySources = getRetrySources(originalSource);
Future<T> resultFuture = null;
final List<Future<T>> futures = new ArrayList<>(retrySources.length);
for (int tryIndex = 0; tryIndex < retrySources.length && resultFuture == null; tryIndex++) {
final int tryIndexCopy = tryIndex;
futures.add(ecs.submit(() -> client.call(retrySources[tryIndexCopy], tryIndexCopy)));
resultFuture = ecs.poll(millisBeforeRetry, TimeUnit.MILLISECONDS);
}
if (resultFuture == null) {
resultFuture = ecs.take();
}
return resultFuture.get();
...我的问题是我正在重写测试以不使用睡眠,而是使用 CountDownLatch
。请参阅下面我的一项测试...
@Test
public void call_firstRetryFinishesAfterLimitButBeforeSecondRetryDoes_triggersSecondRetryButUsesFirstResult() throws Exception {
final String readResult1 = "a";
final String readResult2 = "b";
final CountDownLatch signal1 = new CountDownLatch(1);
final CountDownLatch signal2 = new CountDownLatch(1);
expect(mockReadOperation.call(readOptions[0], 0)).andStubAnswer(() -> {
signal1.await(); // This causes the test to spin forever
// Thread.sleep(1000); // Swapping the line above for this, makes it work
return readResult1;
});
expect(mockReadOperation.call(readOptions[1], 1)).andStubAnswer(() -> {
signal1.countDown();
signal2.await(); // For this test case, make the second retry never return
return readResult2;
});
replay(mockReadOperation);
final ReadOption readOption = ReadOption.primary();
final String result = subject.call(readOption);
assertThat(result).isEqualTo("a");
}
...请注意我的 ExecutorCompletionService
已定义...
private final ExecutorCompletionService executorCompletionService = new ExecutorCompletionService(Executors.newFixedThreadPool(2));
...因为我的测试是 运行 在主线程中,并且每次调用都是 运行 它是自己的线程作为 ExecutorCompletionService
池的一部分,我不理解为什么 signal1.await();
会导致测试永远旋转并注意评论,即切换那条单线以进入睡眠状态会导致测试通过。
非常感谢任何帮助。
这可能是由于 replay(mockReadOperation);
您在何处激活(执行)模拟。 ??
注意:我从未使用过 easy-mock,但快速 google 表明 replay
激活了模拟,这似乎符合答案,我可能错了。
如果我是对的,而你总是需要在 easymock 中进行 replay
模拟,那么也许解决方案是,切换到 Mockito :p!
所以...
我有这个实用程序 class 在初始调用在给定时间后未返回后执行重试(理论上是任何事情),并不断这样做直到任何源 returns 数据或者直到所有人都筋疲力尽。这使用 ExecutorCompletionService
的 .poll
方法来触发何时重试。请参阅以下实用程序代码 class...
final RetrySources[] retrySources = getRetrySources(originalSource);
Future<T> resultFuture = null;
final List<Future<T>> futures = new ArrayList<>(retrySources.length);
for (int tryIndex = 0; tryIndex < retrySources.length && resultFuture == null; tryIndex++) {
final int tryIndexCopy = tryIndex;
futures.add(ecs.submit(() -> client.call(retrySources[tryIndexCopy], tryIndexCopy)));
resultFuture = ecs.poll(millisBeforeRetry, TimeUnit.MILLISECONDS);
}
if (resultFuture == null) {
resultFuture = ecs.take();
}
return resultFuture.get();
...我的问题是我正在重写测试以不使用睡眠,而是使用 CountDownLatch
。请参阅下面我的一项测试...
@Test
public void call_firstRetryFinishesAfterLimitButBeforeSecondRetryDoes_triggersSecondRetryButUsesFirstResult() throws Exception {
final String readResult1 = "a";
final String readResult2 = "b";
final CountDownLatch signal1 = new CountDownLatch(1);
final CountDownLatch signal2 = new CountDownLatch(1);
expect(mockReadOperation.call(readOptions[0], 0)).andStubAnswer(() -> {
signal1.await(); // This causes the test to spin forever
// Thread.sleep(1000); // Swapping the line above for this, makes it work
return readResult1;
});
expect(mockReadOperation.call(readOptions[1], 1)).andStubAnswer(() -> {
signal1.countDown();
signal2.await(); // For this test case, make the second retry never return
return readResult2;
});
replay(mockReadOperation);
final ReadOption readOption = ReadOption.primary();
final String result = subject.call(readOption);
assertThat(result).isEqualTo("a");
}
...请注意我的 ExecutorCompletionService
已定义...
private final ExecutorCompletionService executorCompletionService = new ExecutorCompletionService(Executors.newFixedThreadPool(2));
...因为我的测试是 运行 在主线程中,并且每次调用都是 运行 它是自己的线程作为 ExecutorCompletionService
池的一部分,我不理解为什么 signal1.await();
会导致测试永远旋转并注意评论,即切换那条单线以进入睡眠状态会导致测试通过。
非常感谢任何帮助。
这可能是由于 replay(mockReadOperation);
您在何处激活(执行)模拟。 ??
注意:我从未使用过 easy-mock,但快速 google 表明 replay
激活了模拟,这似乎符合答案,我可能错了。
如果我是对的,而你总是需要在 easymock 中进行 replay
模拟,那么也许解决方案是,切换到 Mockito :p!