You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Axon框架时如何Mock Spring Boot Repository?

解决Axon Saga测试中Spring Repository Mock注入失败的问题

你遇到的问题很典型:Axon的SagaTestFixture会自行创建Saga实例,而不是使用你通过@InjectMocks初始化的那个对象,导致Mockito的Mock注入完全没生效,所以employeeRepository一直是null。下面给你两种可行的解决方案:

方案一:手动注入Mock并注册到Fixture

这种方法不需要Spring Test支持,直接修改测试代码,把Mock的Repository手动注入到Fixture使用的Saga实例中:

修改后的测试代码

@Slf4j
@RunWith(MockitoJUnitRunner.class)
public class ValidationSagaTest {

    @Mock
    private EmployeeRepository employeeRepository;
    private ValidationSaga validationSaga;
    private FixtureConfiguration fixture;

    @Before
    public void setUp() throws Exception {
        // 1. 创建Saga实例
        validationSaga = new ValidationSaga();
        // 2. 用反射注入私有依赖(因为Repository是private且无setter)
        ReflectionTestUtils.setField(validationSaga, "employeeRepository", employeeRepository);
        // 3. 注入Fixture提供的CommandGateway,方便验证命令发送
        ReflectionTestUtils.setField(validationSaga, "commandGateway", fixture.getCommandGateway());

        // 4. 初始化Fixture并注册我们的Saga实例
        fixture = new SagaTestFixture<>(ValidationSaga.class);
        fixture.registerSaga(validationSaga);
    }

    @Test
    public void shouldSendApplyContextCommand_whenEmployeesExists_givenSomeEvent() {
        val correlationId = "correlationId";
        val emp1Code = "emp1Code ";
        val emp2Code = "emp2Code ";
        val emp1Id = "emp1Id ";
        val emp2Id = "emp2Id ";
        val emp3Id = "emp3Id ";
        val emp3Code = "emp3Code ";

        when(employeeRepository.existsById(emp1Id)).thenReturn(true);
        when(employeeRepository.existsById(emp2Id)).thenReturn(true);

        fixture.givenNoPriorActivity()
                .whenAggregate(correlationId)
                .publishes(new NewMatchingDocumentAggregate.MatchingSubmittedEvent(correlationId, emp1Code, emp2Code, emp1Id, emp2Id, emp3Id, emp3Code))
                .expectActiveSagas(1)
                .expectDispatchedCommands(new NewMatchingDocumentAggregate.ApplyContextCommand(correlationId, emp1Code, emp2Code, emp1Id, emp2Id, emp3Id, emp3Code));
    }
}

关键说明

  • 使用ReflectionTestUtils(来自Spring Test模块)可以绕过私有字段的访问限制,直接注入Mock对象
  • 调用fixture.registerSaga()告诉Fixture使用我们预配置好的Saga实例,而不是自行创建
  • 需要确保你的测试依赖中包含spring-test包

方案二:结合Spring Boot Test和Axon的Spring测试支持

如果你的项目已经使用Spring Boot,推荐这种更简洁的方式,让Spring来管理Bean和Mock:

修改后的测试代码

@Slf4j
@SpringBootTest
@RunWith(SpringRunner.class)
public class ValidationSagaTest {

    @MockBean
    private EmployeeRepository employeeRepository;

    @Autowired
    private SagaTestFixture<ValidationSaga> fixture;

    @Test
    public void shouldSendApplyContextCommand_whenEmployeesExists_givenSomeEvent() {
        val correlationId = "correlationId";
        val emp1Code = "emp1Code ";
        val emp2Code = "emp2Code ";
        val emp1Id = "emp1Id ";
        val emp2Id = "emp2Id ";
        val emp3Id = "emp3Id ";
        val emp3Code = "emp3Code ";

        when(employeeRepository.existsById(emp1Id)).thenReturn(true);
        when(employeeRepository.existsById(emp2Id)).thenReturn(true);

        fixture.givenNoPriorActivity()
                .whenAggregate(correlationId)
                .publishes(new NewMatchingDocumentAggregate.MatchingSubmittedEvent(correlationId, emp1Code, emp2Code, emp1Id, emp2Id, emp3Id, emp3Code))
                .expectActiveSagas(1)
                .expectDispatchedCommands(new NewMatchingDocumentAggregate.ApplyContextCommand(correlationId, emp1Code, emp2Code, emp1Id, emp2Id, emp3Id, emp3Code));
    }
}

关键说明

  • @MockBean会让Spring自动替换容器中的EmployeeRepository为Mock实例,Axon的Saga会自动注入这个Mock
  • 需要确保你的项目依赖中包含axon-spring-boot-starter-test(或对应版本的Axon Spring测试依赖)
  • 这种方式不需要手动管理Saga实例,Spring和Axon会协同完成依赖注入

额外建议

  • 你的ValidationSaga上的@Service注解可以移除,因为Axon会自行管理Saga的生命周期,Spring的@Service会额外创建一个无用的实例
  • Saga中的commandGateway标注为transient是正确的,因为Saga需要序列化,而CommandGateway是不可序列化的服务对象

内容的提问来源于stack exchange,提问作者Bartłomiej Adamczyk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:46:41