2013-08-21 22 views
6

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.

  1. 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.
  2. 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ự.
  3. 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 
} 

Trả lời

4

Cách chúng tôi đã lựa chọn để giải quyết này bây giờ là để tiêm tương đương với một người quan sát vào diễn viên (piggybacking trên một logger hiện có mà không được bao gồm trong danh sách trong câu hỏi). Các diễn viên sau đó có thể nói với người quan sát khi nó đã chuyển từ các tiểu bang khác nhau. Trong mã thử nghiệm, chúng tôi thực hiện một hành động rồi đợi thông báo có liên quan từ diễn viên, trước khi tiếp tục và đưa ra các xác nhận.

Trong thử nghiệm chúng tôi có một cái gì đó như thế này:

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 

Tôi không biết nếu có một cách thành ngữ hơn, điều này có vẻ như là một gợi ý hợp lý với tôi.

Các vấn đề liên quan