Сбой модульного теста TestKit для субъекта AbstractPersistentActorWithAtLeastOnceDelivery, созданного с помощью TestActorRef

Я пытаюсь написать модульный тест для одного из моих актеров, который является производным от AbstractPersistentActorWithAtLeastOnceDelivery с использованием TestKit. Мне нужно создать актера с помощью TestActorRef.create(...), так как мне нужно получить базовый актер, чтобы внедрить макеты в реализацию актера.

Мой (упрощенный) актер

public class MyActor extends AbstractPersistentActorWithAtLeastOnceDelivery {

@Override
public Receive createReceive() {
    return receiveBuilder().match(String.class, message -> {
        persist(new MessageSent(message), event -> updateState(event));
    }).match(ConfirmMessage.class, confirm -> {
        persist(new MessageConfirmed(confirm.deliveryId), event -> 
         updateState(event));
    }).matchAny(message -> log.info("Received unexpected message of class {}. 
     Content: {}", message.getClass().getName(), message.toString())).build();

}

 void updateState(Object received) {
    if (received instanceof MessageSent) {
        final MessageSent messageSent = (MessageSent) received;
        ActorRef destinationActor = 
        findDestinationActor(messageSent.messageData);               
        deliver(actorSystem.actorSelection(destinationActor.path()), 
    deliveryId -> new Message(deliveryId, messageSent.messageData));
    } else if (received instanceof MessageConfirmed) {
        final MessageConfirmed messageConfirmed = (MessageConfirmed) received;
        confirmDelivery(messageConfirmed.deliveryId);
    }
}

Модульный тест:

@Test
public void actorTest() {
  ActorSystem system = ActorSystem.create();
  TestKit probe = new TestKit(system);
  TestActorRef<myActor> testActor = TestActorRef.create(system, props, 
     probe.getRef());
  MyActor myActor = testActor.underlyingActor();
  injectMocks(myActor); // my method
  testActor.tell("testMessage", probe.getRef());
  List<Object> receivedMessages = probe.receiveN(1, FiniteDuration.create(3, 
    TimeUnit.SECONDS));

}

В отладчике я вижу, что вызывается метод delivery() внутри updateState(), но модульный тест завершается с ошибкой:

утверждение не удалось: тайм-аут (3 секунды) при ожидании 1 сообщения (получил 0)

Мне интересно, можно ли использовать TestKit для тестирования актера, созданного с помощью TestActorRef, и если тот факт, что мой актер расширяет AbstractPersistentActorWithAtLeastOnceDelivery, имеет какое-то отношение к сбою тестов


person MrkK    schedule 20.03.2018    source источник


Ответы (1)


Невозможно использовать TestActorRef с постоянством Akka. Иногда это работает, но часто терпит неудачу так, как вы описали в своем вопросе. Другие функции TestKit прекрасно работают с персистентностью Akka.

См. предупреждение в разделе https://doc.akka.io/docs/akka/current/testing.html#synchronous-testing-testactorref:

Предупреждение

Из-за синхронного характера TestActorRef он не будет работать с некоторыми трейтами поддержки, предоставляемыми Akka, поскольку для их правильной работы требуется асинхронное поведение. Примерами признаков, которые плохо сочетаются со ссылками на тестовых субъектов, являются PersistentActor и AtLeastOnceDelivery, предоставляемые Akka Persistence.

person Frederic A.    schedule 21.03.2018
comment
Означает ли это, что постоянный актор, который использует внедрение зависимостей, не может быть протестирован? Для внедрения моков или реальных зависимостей потребуется доступ к экземпляру класса актеров, и это можно сделать только через TestActorRef. - person MrkK; 22.03.2018
comment
Возможно, вы могли бы обойти это, протестировав что-то вроде class MyActorUnderTest extends MyActor, в котором вы устанавливаете свои макеты перед созданием актера. - person Frederic A.; 22.03.2018