我有一个针对Akka演员的Scala单元测试。该actor旨在轮询远程系统并更新本地缓存。演员设计的一部分是它在处理或等待上次轮询的结果时不会尝试轮询,以避免在远程系统经历减速时泛滥。
我有一个测试用例(如下所示),它使用Mockito来模拟慢速网络呼叫,并检查当告知演员更新时,它将不再进行另一次网络呼叫,直到当前完成。它通过验证与远程服务缺乏交互来检查演员是否还没有进行另一次调用。
我想取消对Thread.sleep
的号召。我想测试演员的功能而不依赖于等待硬编码时间,在每次测试运行中都很脆弱,浪费时间。测试可以轮询或阻止,等待条件,超时。这将更加强大,并且在测试通过时不会浪费时间。我还有一个额外的约束,我希望保持用于阻止额外轮询var allowPoll
限制范围的状态到PollingActor
的内部。
java.util.concurrent.AtomicBoolean
。我已经完成了这个并且代码似乎有效,但我对Akka的了解不足以知道它是否沮丧 - 一位同事推荐了自我消息风格。当前演员看起来像这样:
class PollingActor(val remoteService: RemoteServiceThingy) extends ActWhenActiveActor {
private var allowPoll: Boolean = true
def receive = {
case PreventFurtherPolling => {
allowPoll = false
}
case AllowFurtherPolling => {
allowPoll = true
}
case UpdateLocalCache => {
if (allowPoll) {
self ! PreventFurtherPolling
remoteService.makeNetworkCall.onComplete {
result => {
self ! AllowFurtherPolling
// process result
}
}
}
}
}
}
trait RemoteServiceThingy {
def makeNetworkCall: Future[String]
}
private case object PreventFurtherPolling
private case object AllowFurtherPolling
case object UpdateLocalCache
在specs2中的单元测试看起来像这样:
"when request has finished a new requests can be made" ! {
val remoteService = mock[RemoteServiceThingy]
val actor = TestActorRef(new PollingActor(remoteService))
val slowRequest = new DefaultPromise[String]()
remoteService.makeNetworkCall returns slowRequest
actor.receive(UpdateLocalCache)
actor.receive(UpdateLocalCache)
slowRequest.complete(Left(new Exception))
// Although the test calls the actor synchronously, the actor calls *itself* asynchronously, so we must wait.
Thread.sleep(1000)
actor.receive(UpdateLocalCache)
there was two(remoteService).makeNetworkCall
}
答案 0 :(得分:4)
我们现在选择解决这个问题的方法是将一个观察者的等价物注入演员(捎带现有的记录器,这个记录器没有包含在问题列表中)。然后,演员可以告诉观察者它何时从各种状态转变。在测试代码中,我们执行一个操作,然后在继续并进行断言之前等待来自actor的相关通知。
在测试中我们有类似的东西:
actor.receive(UpdateLocalCache)
observer.doActionThenWaitForEvent(
{ actor.receive(UpdateLocalCache) }, // run this action
"IgnoredUpdateLocalCache" // then wait for the actor to emit an event
}
// assert on number of calls to remote service
我不知道是否有更惯用的方式,这对我来说似乎是一个合理的建议。