chhu
chhu

Reputation: 41

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?

Upvotes: 1

Views: 48

Answers (2)

Steven
Steven

Reputation: 7275

Although the solution you have works, @chhu, Axon's Test Fixtures actually have a dedicated method to register external command handlers!

This is the FixtureConfiguration#registerAnnotatedCommandHandler(Object) method. Knowing that, your sample code could look like this:

FixtureConfiguration<MyAggregate> testFixture = new AggregateTestFixture<>(MyAggregate.class);
testFixture.registerAnnotatedCommandHandler(new ExternalCommandHandler(aggregateRepository));

// perform testing here...

Although I recognize this reply is late, I figured it would be helpful regardless.

Upvotes: 0

chhu
chhu

Reputation: 41

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

}

Upvotes: 0

Related Questions