springkotlintestingintegration-testingaxon

Axon Command Handling Tests in a Spring Enviorment


I would like to test an external Axon command-handler. It's getting via constructor DI an Axon-Repository.

This test-case should be as minimalistic and fast, as possible. It should test, whether on a given command, given Events were executed.

class CommandHandlingTests {

private val fixture = AggregateTestFixture(ExternalCommandHandler::class.java)

    @Test
    fun `Test Command Handling`() {
        val uuid = UUID.randomUUID()
        val title = "New Qualification"
        fixture
            .given()
            .`when`(MyCommand(uuid.toString(), title))
            .expectSuccessfulHandlerExecution()
            .expectEvents(MyEvent(uuid, title))
    }
}


@Component
class ExternalCommandHandler(val qualificationRepository: Repository<MyAggregate>) {

    @CommandHandler
    fun handle(command: MyCommand) {
        qualificationRepository.newInstance {
            MyAggregate.create(UUID.fromString(command.uuid), command.title)
        }
    }

}

Problem is, that whe are developing axon in a spring env, so the external command-handlers get injected with spring beans. (for example, the repo).

  1. Problem: Given test case is failing, because axon is expecting an empty constructor. Is it possible, to inject the necessary dependencies myself, without creating a spring boot test?

  2. What would be the minimalistic approach to test simple "event has been thrown as a result of command on aggregate" in a spring env? How could I mock in this layer, the necessary dependencies, as minimalistic, as possible?


Solution

  • After some research, I have considered the following solution for our use-cases:

    Firstly, I have accepted, that axon requires an empty constructor. Therefore I have made use of the @Autowired Annotation and setter-based DI of Spring.

    @Component
    class ExternalCommandHandler {
    
        @Autowired
        public lateinit var aggregateRpository: Repository<MyAggregate>
    
        @CommandHandler
        fun handle(command: MyCommand) {
            aggregateRpository.newInstance {
                MyAggregate.create(UUID.fromString(command.uuid), command.title)
            }
        }
    }
    

    I have written an Configuration-File for all Dependencies that shall be injected by Spring.

    @Configuration
    class TestCommandHandlerConfiguration {
        @Bean
        fun myAggregateRepository(eventStore: EventStore) : Repository<Qualification> {
            return EventSourcingRepository.builder(MyAggregate::class.java).eventStore(eventStore).build()
        }
    }
    

    Lastly I have configured those dependencies in my integration-test, to be loaded at runtime:

    @RunWith(SpringRunner::class)
    @ContextConfiguration(classes = [(TestCommandHandlerConfiguration::class)])
    class CommandHandlingTest {
    
        private val fixture = AggregateTestFixture(ExternalCommandHandler::class.java)
    
        @Test
        fun `Test Command Handling`() {
            val uuid = UUID.randomUUID()
            val title = "New Qualification"
            fixture
                .given()
                .`when`(MyCommand(uuid.toString(), title))
                .expectSuccessfulHandlerExecution()
                .expectEvents(MyEvent(uuid, title))
        }
    

    }