2014-11-02 4 views
0

PersistentActor에서 컨텍스트를 사용할 때 이상한 동작이 발생합니다 (지속성이 문제의 원인과 관련이 있는지 확실하지 않음). 내 코드는 다음과 같습니다.Akka의 컨텍스트. 이상한 동작으로

class MyActor extends PersistentActor { 

    import context._ 

    // Messages 
    case object Start 
    case object Ready 
    case object MessageX 

    // Events 
    case object Started 

    def recieveRecover: Receive = { /* Not relevant, I think */} 

    def receiveCommand: Receive = idle 

    def idle: Receive = { 
     case Start => 
      persist(Started) { _ => 
       sender() ! Ready 
       become(ready) 
      } 
    } 

    def ready: Receive = { 
     case MessageX => doSomething() 
    } 
} 

그리고 동일한 MyActorSpec 파일에서 두 가지 테스트가 있습니다. 첫 번째는 단순히 '대기'상태를 테스트하고 두 번째는 '준비'상태를 테스트합니다

"Test A" in { 
    val actorRef = system.actorOf(MyActor.props(), "test-A-actor") 

    actorRef ! Start 

    expectMsg(Ready) 
} 

"Test B" in { 
    val actorRef = system.actorOf(MyActor.props(), "test-B-actor") 

    actorRef ! Start 

    expectMsg(Ready) /* It fails here because for some reason the actorRef 
    was created with its 'receiveCommand' block equal to 
    the 'ready' block and not equal to the 'idle' block as its suppossed to. 
    So it timeouts here waiting for the message which is not handled in 
    the 'ready' block */ 

    actorRef ! MessageX 

    testSomethingAboutTheMessageX() 
} 

내가 두 테스트를 실행하는 경우, 첫 번째는 성공하지만 두 번째는 준비 메시지를 기다리는 실패 (로 두 번째 테스트에서 주석에서 설명했다). 두 번째 테스트 만 통과하면 통과합니다. 그래서 액터를 정의 할 때 내가 뭔가 잘못했는지 확신 할 수 없습니다.

UPDATE : (두 배우가 idle 상태에서 만든) 내가 제안으로 Started 이벤트에 대한 지속성합니다 (persist(Started) 부분)를 제거하려 예상대로 테스트를했다. 따라서, 첫 번째 액터 인스턴스의 이벤트가 지속되고 두 번째 액터 인스턴스가이를 재생하고 있으며 이는 액터 인스턴스가 동일한 persistenceId (DOH!)으로 생성되므로 발생합니다. 따라서 테스트를 독립적으로 만드는 방법은 각각의 액터를 다른 persistenceId으로 인스턴스화하는 것입니다.

+0

어떤 테스트가 실행되는지에 따라 결과가 변경된다는 사실은 테스트가 독립적이지 않다는 것을 나타냅니다. 공유 상태가 없음을 확인하기 위해 각 테스트 내에서 새로운 '시스템'을 만드는 것이 좋습니다. – millhouse

답변

2

첫 번째 액터 인스턴스의 이벤트가 지속되고 두 번째 액터 인스턴스가이를 재생하고있는 것은 액터 인스턴스가 동일한 persistenceId (DOH!)으로 생성 되었기 때문입니다. 따라서 테스트를 독립적으로 만드는 방법은 각각의 액터를 다른 persistenceId으로 인스턴스화하는 것입니다.

0

'순차적'인수에 기본값 'false'가 있기 때문에 모든 테스트를 동시에 실행하는 Specs2가 원인 일 수 있습니다.

class MyActorSpec extends Specification { 

    // Run the tests sequentially 
    sequential 


    "MyActor" should { 
    "Test A" in { 
      // test goes here 
    } 
    "Test B" in { 
      // test goes here 
    } 
    } 
} 

자세한 것은 http://etorreborre.github.io/specs2/guide/org.specs2.guide.Runners.html 에서보세요 :

는 사양의 상단에 이런 일을 순차적를 지정, 모든 테스트가 잇달아 실행 강제로.

+0

음, 아니야.이게 그럴 것 같지 않아. 나는 scalatest를 사용 중이며 순차적으로 테스트를 수행했고 동일한 동작을 보였다. 나는 그것이 문제가 아니라고 생각한다. 왜냐하면 그들이 병렬로 실행되고 있어도 서로 다른 액터 인스턴스를 사용하기 때문에 겹치지 않아야하기 때문이다. – miguel

+0

사실 그렇지만 두 테스트 모두 동일한 액터 시스템을 공유하며 expectMsg()에서 액터의 응답을받는 데 동일한 암시 적 보낸 사람 액터가 사용됩니다. 그래서 A 액터 B가 보낸 Ready 응답이 Test A에서 수신 될 때 경쟁 조건을 가질 수 있습니다. –

+0

'ready Start => println ("Started in!") 절을'ready'recieve 블록에 추가하고 두 번째 테스트가 그것을 인쇄합니다. 따라서 문제는 '준비'메시지를 수신 한 첫 번째 테스트가 아니므로 두 번째 테스트에서 시간 초과를 유발하는 것이 아니라 두 번째 테스트에서 해당 수신 블록이 '대기'가 아닌 '준비'로 설정된 액터를 생성합니다. – miguel