External command handler testing

I’m not able to guess how external command handlers are expected to be tested.

The primary reason for having an external command handler was that I have complex logic that is purely application/technical related, which I do not want to be polluting my aggregate.

I’m calling the execute method and passing a Consumer, so I have access to aggregate state properties that are essential do the calculations being executed. In the end, I pass the command back to the aggregate so the state can be modified.

I tried those different approaches:

  • Mock the Aggregate and Repository interfaces, which forces me to configure the load (straightforward) and execute methods, and execute the Consumer being passed by the command handler; I also have to provide the Aggregate itself

  • instantiate one (it complains about State not being defined)

  • or mock (which is not possible because I set my aggregate as final)- Use the AggregateTestFixture, obtain the repository from it, and pass the Repository to the command handler so that the Aggregate can be retrieved again from it.

  • It complains about unitOfWork not being started

It’s written in Docblock of the aggregate execute method that you are not supposed to be calling it, as you should not receive access to the Aggregate and not be able to manipulate its internals. I believe however that this advice is there mostly to avoid people from interacting it from the read side. As the command handlers that are in the aggregate have full access to the state itself, it felt natural to me that I could access this aggregate directly, at least for reading purposes.

I also think the documentation on the external command handler is very poor.

Hi Fabio,

whether a command handler is external or internal to the aggregate, shouldn’t change much in the testing strategy. I would recommend using the AggregateTestFixtures, which you would instantiate with your aggregate’s class. Then, in the FixtureConfiguration instance you get, you can register an instance of your external command handler, which you can initialize using the repository from the Fixture.

Instead of invoking your external command handler directly, you should use the given() to set up the expected state of your aggregate (either through events, recommended, or by specifying the actual state of the aggregate) and the when() to pass a command that you want executed. Lastly, you can verify the behavior checking for published events, aggregate state (only relevant when not using event sourcing) and optionally any invocations of mocks that you may have provided in your command handler.

Hope this helps.