在 Spring 中配置 Axon 以进行集成测试

Configuring Axon in Spring for integration testing

java 和 axon 还是新手,使用 spring 和 axon 设置集成测试套件时遇到问题。

基本上,我有一些流程,其中:

我使用 axon tests 进行单元测试,效果很好。

但我想将“集成”测试添加到:

  1. 检查整个流程,例如:当 command1 被调度时,event1、event2、event3 被记录(实际上不关心字段,只是为了确信整个事情按预期粘合)
  2. 检查服务命令处理程序是否按预期方式工作“当命令 2 被调度时,然后事件 2 被记录”

我通过以下方式部分成功了 1):

package com.example.integration;

import org.axonframework.commandhandling.gateway.CommandGateway;
import org.axonframework.eventsourcing.eventstore.EmbeddedEventStore;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.Arrays;
import java.util.UUID;

@RunWith(SpringRunner.class)
@SpringBootTest
@Import(IntegrationTestConfig.class)
public class ExampleIntegrationTest
{

    @Autowired
    private CommandGateway commandGateway;

    @Autowired
    private EmbeddedEventStore eventStore;

    @Test
    public void itShouldStoreCorrectEvents() {
        var aggregateId = UUID.randomUUID().toString();
        var exampleCommand = new ExampleCommand(aggregateId);

        whenCommandIsDispatched(exampleCommand);

        thenExpectedEventsRecorded(
                Arrays.asList(
                        Event1.class,
                        Event3.class
                ),
                aggregateId
        );
    }

    private void whenCommandIsDispatched(Command command)
    {
        commandGateway.sendAndWait(command);
    }

    private void thenExpectedEventsDispatched(java.util.List<Class<?>> expectedEventTypes, String id)
    {
        var events = eventStore.readEvents(id);
        while (events.hasNext()) {
            Assert.assertEquals(
                    expectedEventTypes.get(Math.toIntExact(events.getLastSequenceNumber())),
                    events.next().getPayloadType()
            );
        }
    }
}

并拥有 IntegrationConfigTest:

package com.example.library.test;

import org.axonframework.eventhandling.EventBus;
import org.axonframework.eventsourcing.eventstore.EmbeddedEventStore;
import org.axonframework.eventsourcing.eventstore.EventStorageEngine;
import org.axonframework.eventsourcing.eventstore.inmemory.InMemoryEventStorageEngine;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;

@TestConfiguration
public class IntegrationTestConfig {

    @Bean
    @Primary
    public static EventBus createSpyEventBus() {
        return new EmbeddedEventStore.Builder().storageEngine(new InMemoryEventStorageEngine()).build();
    }
}

很好,测试通过了,但我没有找到如何测试从服务命令处理程序(在我的示例中为 Event2)调度的事件的方法 - 此处需要聚合 ID:eventStore.readEvents(id)。编辑:但我不想将聚合 ID 放入,因为事件未记录在任何聚合上 - 它被直接发送到 service/singleton 命令处理程序中的事件网关。

关于如何获取所有已分派的事件以便我也可以断言 Event2 已分派的任何想法?

或者我在这里遗漏了什么? :)

接收 command1 以创建聚合的初始化命令处理程序可能 return aggregateId,因此您可以获取 returned 结果并使用该 id 以供将来参考。

 ...
 public class MyAggregate {
     @CommandHandler
     public static MyAggregate create(CreateCmd cmd) {
          MyAggregate a = new MyAggregate();
          AggregateLifecycle.apply(new CreatedEvent(UUID.randomUuid().toString());
          return a;
     }
 }
 ....

 String generatedId = commandGateway.sendAndWait(new CreateCmd(null));
 .... // continue

如果要验证 EventStore 中的事件,可以使用 EventStore#openStream(TrackingToken) 操作。

这将打开商店中包含的事件流,从一个可定义的(读作:TrackingToken)时间点开始。通过调整您提供的令牌,您可以选择起始位置。要构造令牌,您可以再次使用 EventStore,它提供以下操作:

  • createTailToken() - 从开头开始流
  • createHeadToken() - 在最后开始流
  • createTokenAt(Instant dateTime) - 在 Instant
  • 开始播放
  • createTokenSince(Duration duration) - 从 Duration
  • 开始流式传输

鉴于您的测试范围较小,我认为 createTailToken 就可以了。