我试图在我的单元测试中获得演员的内部状态,但由于某种原因旧状态仍然存在。
我的演员应该添加/删除/列出自我注册的演员服务:
class DirectoryServiceActor extends Actor {
var servicesMap: Map[String, List[ActorRef]] = Map.empty[String, List[ActorRef]]
def receive = {
case AddService(serviceType) ⇒
servicesMap = servicesMap + (serviceType -> (sender :: servicesMap.getOrElse(serviceType, List.empty[ActorRef])))
sender ! Ack
case RemoveService ⇒
val oldMap = servicesMap
servicesMap = servicesMap.mapValues(list ⇒ (if (list.contains(sender)) list.diff(List(sender)) else list).toList)
println(servicesMap)
if (servicesMap.equals(oldMap)) {
sender ! Nack
} else {
sender ! Ack
}
case ListServices ⇒
sender ! services
}
def services: Map[String, List[ActorRef]] = this.servicesMap
}
我的测试是
"Remove existing service successfully" in {
implicit val timeout = 10 millis
val probe = new TestProbe(system)
val directoryService = TestActorRef[DirectoryServiceActor]
val actor = directoryService.underlyingActor
directoryService.tell(AddService("test"), probe.ref)
probe.expectMsg(timeout, Ack)
directoryService.tell(RemoveService, probe.ref)
probe.expectMsg(timeout, Ack)
println("TEST: " + actor.services)
actor.services("test") should not contain (probe.ref)
}
根据测试和控制台输出失败判断,似乎actor.underlyingActor.services返回旧值:
Map(test -> List())
TEST: Map(test -> List(Actor[akka://myApp/system/testActor3#-2080677614]))
即使在actor内部,该变量也已设置为新值。我错过了什么?
更新:实际上似乎与Akka无关,但可以在测试中使用期货来解决:
"Remove existing service successfully" in {
implicit val timeout = Timeout(100 millis)
val directoryService = TestActorRef[DirectoryServiceActor]
val addResponseFuture = directoryService ? AddService(self, "test")
addResponseFuture.value.get should be(Success(Ack(self)))
val removeResponseFuture = directoryService ? RemoveService(self)
removeResponseFuture.value.get should be(Success(Ack(self)))
val listResponseFuture = directoryService ? ListServices
listResponseFuture.value.get should be(Success(Map("test" -> List())))
val actor = directoryService.underlyingActor
actor.services("test") should not contain (self)
}
我认为由于mapValue实际上没有创建新地图而发生这种情况:Scala: Why mapValues produces a view and is there any stable alternatives?
答案 0 :(得分:2)
出于某种原因,我认为mapValues
正是导致问题的原因。尝试更改RemoveService
处理,如下所示:
case RemoveService =>
val oldMap = servicesMap
servicesMap = servicesMap.map{
case (key, list) => (key, list.filterNot(_ == sender))
}
if (servicesMap.equals(oldMap)) {
sender ! Nack
} else {
sender ! Ack
}