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).
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?
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?
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))
}
}