Tôi có một bài kiểm tra đơn vị Scala cho một diễn viên Akka. Các diễn viên được thiết kế để thăm dò ý kiến một hệ thống từ xa và cập nhật một bộ nhớ cache cục bộ. Một phần của thiết kế của diễn viên là nó không cố gắng thăm dò trong khi nó vẫn đang xử lý hoặc chờ kết quả của cuộc thăm dò cuối cùng, để tránh làm ngập hệ thống từ xa khi nó bị chậm lại.Làm thế nào để đơn vị kiểm tra một diễn viên Akka gửi một tin nhắn cho chính nó, mà không sử dụng Thread.sleep
Tôi có một trường hợp kiểm tra (được hiển thị bên dưới) sử dụng Mockito để mô phỏng cuộc gọi mạng chậm và kiểm tra khi tác nhân được thông báo cập nhật, nó sẽ không thực hiện cuộc gọi mạng khác cho đến khi cuộc gọi hiện tại hoàn tất. Nó kiểm tra các diễn viên đã không thực hiện cuộc gọi khác bằng cách xác minh sự thiếu tương tác với dịch vụ từ xa.
Tôi muốn loại bỏ cuộc gọi đến Thread.sleep
. Tôi muốn kiểm tra chức năng của diễn viên mà không phải chờ đợi thời gian hardcoded, trong mọi lần chạy thử, đó là giòn, và lãng phí thời gian. Bài kiểm tra có thể thăm dò ý kiến hoặc chặn, chờ một điều kiện, với thời gian chờ. Điều này sẽ mạnh mẽ hơn, và sẽ không lãng phí thời gian khi bài kiểm tra trôi qua. Tôi cũng có thêm ràng buộc mà tôi muốn giữ trạng thái được sử dụng để ngăn chặn việc bỏ phiếu thêm var allowPoll
giới hạn phạm vi, đối với nội bộ của PollingActor
.
- có cách nào chờ đợi cho đến khi diễn viên tự hoàn tất nhắn tin không? Nếu có một cách tôi có thể đợi cho đến lúc đó trước khi cố gắng khẳng định.
- là cần thiết để gửi tin nhắn nội bộ? Tôi không thể duy trì trạng thái nội bộ với cơ sở hạ tầng luồng an toàn, chẳng hạn như
java.util.concurrent.AtomicBoolean
. Tôi đã làm điều này và đoạn mã dường như hoạt động, nhưng tôi không đủ hiểu biết về Akka để biết nếu nó không được khuyến khích - một đồng nghiệp đã đề xuất phong cách nhắn tin tự. - có tốt hơn, chức năng ngoài hộp với cùng ngữ nghĩa không? Sau đó, tôi sẽ lựa chọn không cho một bài kiểm tra tích hợp thay vì một bài kiểm tra đơn vị, mặc dù tôi không chắc chắn nếu nó sẽ giải quyết vấn đề này.
Các diễn viên hiện nay trông giống như sau:
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
Và kiểm tra đơn vị, trong specs2, trông như thế này:
"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
}