【问题标题】:Test that an akka actor receives a set of different types of messages without guaranteeing order在不保证顺序的情况下测试 akka actor 是否接收到一组不同类型的消息
【发布时间】:2016-08-06 08:27:53
【问题描述】:

TL;DR:

我不知道如何在不保证消息顺序的情况下测试 Akka actor 是否接收到一组不同类型的消息。

具体说明:

我正在测试某些域事件已发布到akka.event.EventStream。为此,我为所有DomainEvent 子类订阅了TestProbe

val eventBusTestSubscriber = TestProbe()(actorSystem)
actorSystem.eventStream.subscribe(eventBusTestSubscriber.ref, classOf[DomainEvent])

这样,我可以测试出单个域事件到达EventStream,而不考虑其他可能的事件(避免脆弱测试):

规格:

shouldPublishDomainEvent {
  event: WinterHasArrivedDomainEvent =>
    event.isReal shouldBe true
    event.year shouldBe expectedYear
}

助手特质:

def shouldPublishDomainEvent[EventType](eventAsserter: EventType => Unit)
  (implicit gotContext: GotContextTest, classTag: ClassTag[EventType]): Unit = {

  val receivedEvent = gotContext.eventBusTestSubscriber.receiveN(1).head

  receivedEvent match {
    case event: EventType =>
      eventAsserter(event)

    case _ =>
      shouldPublishDomainEvent(eventAsserter)
  }
}

我还对以下场景进行了一些测试,在这些场景中我应该接收一组相同类型的事件以保证订单,而不考虑其他可能的事件(避免脆弱测试):

规格:

val someoneDiedEventAsserter: SomeoneDiedDomainEvent => Unit = { event =>
  event.isReal shouldBe false
  event.episodeId shouldBe episodeId
}

val someoneDiedEventIdExtractor = (event: SomeoneDiedDomainEvent) => event.characterId

shouldPublishDomainEventsOfType(someoneDiedEventAsserter, someoneDiedEventIdExtractor)(characterIdsToDie)

助手特质:

def shouldPublishDomainEventsOfType[EventType, EventIdType](
  eventAsserter: EventType => Unit,
  eventIdExtractor: EventType => EventIdType
)(expectedEventIds: Set[EventIdType])
  (implicit gotContext: GotContextTest, classTag: ClassTag[EventType]): Unit = {

  if (expectedEventIds.nonEmpty) {
    val receivedEvent = gotContext.eventBusTestSubscriber.receiveN(1).head

    receivedEvent match {
      case event: EventType =>
        eventAsserter(event)
        val receivedEventId = eventIdExtractor(event)
        expectedEventIds should contain(receivedEventId)
        shouldPublishDomainEventsOfType(eventAsserter, eventIdExtractor)(expectedEventIds - receivedEventId)

      case _ =>
        shouldPublishDomainEventsOfType(eventAsserter, eventIdExtractor)(expectedEventIds)
    }
  }
}

现在的问题在于我必须测试我正在发布一组具有不同类型且没有保证顺序的事件的用例。

我不知道如何解决的问题是,在shouldPublishDomainEventsOfType 的情况下,我有一个推断的EventType,它为我提供了类型,以便在eventAsserter: EventType => Unit。但是由于我有不同的具体类型的事件,我不知道如何指定它们的类型等等。

我尝试了一种基于包含断言函数的案例类的方法,但问题是一样的,我有点卡住了:

case class ExpectedDomainEvent[EventType <: DomainEvent](eventAsserter: EventType => Unit)

def shouldPublishDomainEvents[EventType](
  expectedDomainEvents: Set[ExpectedDomainEvent]
)(implicit chatContext: ChatContextTest): Unit = {

  if (expectedDomainEvents.nonEmpty) {
    val receivedEvent = chatContext.eventBusTestSubscriber.receiveN(1).head

    expectedDomainEvents.foreach { expectedDomainEvent =>

      val wasTheReceivedEventExpected = Try(expectedDomainEvent.eventAsserter(receivedEvent))

      if (wasTheReceivedEventExpected.isSuccess) {
        shouldPublishDomainEvents(expectedDomainEvents - receivedEvent)
      } else {
        shouldPublishDomainEvents(expectedDomainEvents)
      }
    }
  }
}

谢谢!

【问题讨论】:

    标签: scala akka scalatest akka-testkit


    【解决方案1】:

    感谢Artur Soler :)

    这里有解决方案,以防万一它对任何人都有帮助:

    case class ExpectedDomainEventsOfType[EventType <: DomainEvent, EventId](
      eventAsserter: EventType => Unit,
      eventIdExtractor: EventType => EventId,
      expectedEventIds: Set[EventId]
    )(implicit expectedEventTypeClassTag: ClassTag[EventType]) {
    
      def isOfEventType(event: DomainEvent): Boolean = expectedEventTypeClassTag.runtimeClass.isInstance(event)
    
      def withReceivedEvent(event: DomainEvent): ExpectedDomainEventsOfType[EventType, EventId] = event match {
        case asExpectedEventType: EventType =>
          eventAsserter(asExpectedEventType)
    
          val eventId = eventIdExtractor(asExpectedEventType)
          expectedEventIds should contain(eventId)
    
          copy(expectedEventIds = expectedEventIds - eventId)
      }
    }
    
    def shouldPublishDomainEvents(
      expectedEvents: Set[ExpectedDomainEventsOfType[_, _]]
    )(implicit gotContext: GotContextTest): Unit = {
    
      if (expectedEvents.nonEmpty) {
        val receivedEvent = gotContext.eventBusTestSubscriber.receiveN(1).head.asInstanceOf[DomainEvent]
    
        expectedEvents.find(expectedEventsOfType => expectedEventsOfType.isOfEventType(receivedEvent)) match {
          case Some(expectedEventsOfReceivedType) =>
            val expectedEventsWithoutTheReceived = expectedEventsOfReceivedType.withReceivedEvent(receivedEvent)
    
            if (expectedEventsWithoutTheReceived.expectedEventIds.isEmpty) {
              shouldPublishDomainEvents(expectedEvents - expectedEventsOfReceivedType)
            } else {
              shouldPublishDomainEvents(expectedEvents - expectedEventsOfReceivedType + expectedEventsWithoutTheReceived)
            }
    
          case None =>
            shouldPublishDomainEvents(expectedEvents)
        }
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-22
      • 1970-01-01
      • 1970-01-01
      • 2015-05-29
      • 2019-04-29
      • 1970-01-01
      相关资源
      最近更新 更多