AssertJ和Awaitility是在自动代码测试中使用的两个我最喜欢的工具。 不幸的是直到最近,还不能一起使用它。 但是随后Java 8进入了游戏,几十行代码足以使其在Awaility 1.6.0中实现。
AssertJ提供了一组丰富的断言,其中包含非常有用的错误消息,所有这些消息都可以通过流畅的类型识别 API获得。 Awaitility允许表达简明异步调用的期望和易于阅读的方式利用其缩短测试时间的积极等待模式(没有更多的睡眠(5000)!)。
一年前,当我正在使用复杂事件处理 (CEP)进行算法交易项目时,就想到了将其一起使用的想法,而且我不喜欢仅针对具有Awaitility的异步测试学习Hamcrest断言。 我能够进行工作的PoC ,但是它需要在AssertJ(然后是FEST Assert)代码中进行一些重要的复制,因此我搁置了这个想法。 一个月前,我正在为4Developers会议准备有关异步代码测试的演示文稿,并问自己一个问题:Java 8如何简化Awaitility的使用?
在少数示例中,我将使用asynchronousMessageQueue
消息队列,该消息可用于发送ping请求并返回接收到的数据包的数量。 用Java 7中的Awaitility(基于代理的条件除外)对其进行测试的一种方法是创建一个Callable
类实例:
@Test
public void shouldReceivePacketAfterWhileJava7Edition() {
//when
asynchronousMessageQueue.sendPing();
//then
await().until(receivedPackageCount(), equalTo(1));
}
private Callable<Integer> receivedPackageCount() {
return new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return asynchronousMessageQueue.getNumberOfReceivedPackets();
}
};
}
其中equalTo()
是标准的Hamcrest匹配器。
减少冗长的第一个想法是用lambda表达式替换Callable
并内联private方法:
@Test
public void shouldReceivePacketAfterWhile() {
//when
asynchronousMessageQueue.sendPing();
//then
await().until(() -> asynchronousMessageQueue.getNumberOfReceivedPackets(), equalTo(1));
}
好多了。 以后的lambda表达式可以用方法参考代替:
@Test
public void shouldReceivePacketAfterWhile() {
//when
asynchronousMessageQueue.sendPing();
//then
await().until(asynchronousMessageQueue::getNumberOfReceivedPackets, equalTo(1));
}
有人甚至可以进一步删除Hamcrest匹配器:
@Test
public void shouldReceivePacketAfterWhile() {
//when
asynchronousMessageQueue.sendPing();
//then
await().until(() -> asynchronousMessageQueue.getNumberOfReceivedPackets() == 1); //poor error message
}
但是尽管它仍然可以正常工作,但错误消息的意义变得不那么重要了:
ConditionTimeoutException: Condition with lambda expression in
AwaitilityAsynchronousShowCaseTest was not fulfilled within 2 seconds.
而不是很清楚:
ConditionTimeoutException: Lambda expression in AwaitilityAsynchronousShowCaseTest
that uses AbstractMessageQueueFacade: expected <1> but was <0> within 2 seconds.>
解决方案是在lambda表达式中使用AssertJ断言:
@Test
public void shouldReceivePacketAfterWhileAssertJEdition() {
//when
asynchronousMessageQueue.sendPing();
//then
await().until(() -> assertThat(asynchronousMessageQueue.getNumberOfReceivedPackets()).isEqualTo(1));
}
并且由于新的AssertionCondition最初在几分钟之内就被黑客入侵,因此在Awaitility 1.6.0中成为了现实。 当然,会保留AssertJ流利的API和针对不同数据类型的有意义的故障消息。
作为奖励,所有引发AssertionError的断言(尤其是TestNG和JUnit标准断言)也可以在lambda表达式中使用(但我不知道有人知道AssertJ的功能回到了“标准”断言中)。
令人高兴的是, 更改本身利用Runnable类来实现lambda和AssertJ支持,而Awaitility 1.6.0仍与Java 5兼容。 但是,出于可读性考虑,仅在基于Java 8的项目中使用新结构才有意义。
顺便说一句,这是我在4Developers上的演讲的“ 幻灯片 ”。