Correct way to register and test a unit of work

It’s been a few years since I’ve actively used Axon (and it was 2.x back then) so I’m a lot rusty and not sure where I should be adding transactional work.

The problem:
I’ll be integrating with multiple AWS messaging services and I’d like control over when in the chain each message sent. It seems like I remember something about registering a Unit of Work but I don’t remember exactly where or how.

More importantly:
What is the correct way to add tests to verify how I’ve wired this up, are there test fixtures for this? (more important because if I get this figured out then the above questions should be easy to figure out)

Let me know if I’m headed down the wrong track altogether.

Thanks!
Dave

Hi Dave,

good to hear that you’re back to using Axon again.
The Unit of Work is indeed the best location to orchestrate this. You can use it to attach actions to specific phases, such as onPrepareCommit, commit or aftercommit. You can also attach resources to the unit of work. Both these mechanisms could be useful.
To obtain the current Unit of Work, you can either declare a parameter of type UnitOfWork in your @EventHandler or @CommandHandler method, or use the static CurrentUnitOfWork.get() method.

Depending on the level of transaction support you have on the calls to the external system, you may want to “buffer” these messages before sending them. If it does support transactions, you probably don’t have to, and can just do unitOfWork.onCommit(u -> externalSystem.commitTX()).
A typical pattern when buffering data is to do:
unitOfWork.getOrComputeResource(“someUniqueBufferName”, k -> {
List<…> buffer = new ArrayList<>();
unitOfWork.onCommit(u -> { do activity to publish content of buffer}
return buffer;
}).add(myTaskToAddToTheList);

is there is no concurrency on the unit of work, the structure with the getOrCompute() will ensure the creation is only invoked once, and thus only a single onCommit handler is registered.

Hope this helps.

Cheers,

Allard

Thanks Allard,

So it seems like the best place to test this would be using a FixtureConfiguration as I would test command handlers? (or in the actual command handler tests themselves?)

Is there a way to access the events that have been applied? Or is that even appropriate at this stage? The reason is that we’re considering publishing our events to an eventstream that multiple other applications may monitor.

Thanks!
Dave

bump.

Hi Dave,

actually, the tests Fixtures are only designed to test Aggregates or Sagas themselves. It seems more like you want to create a component that interacts with an external system, triggered by events, but that you expect that component to hook into the Unit of Work.

I’d recommend just creating a “regular” test case, where you create a Unit of Work (use DefaultUnitOfWork.startAndGet() ). In some tests you commit, in some you roll back, etc.

If you work with Unit of Work in your test cases, it is recommended to put this in your “tearDown” method:

while (CurrentUnitOfWork.isStarted()) {
CurrentUnitOfWork.get().rollback();
}

This ensures no lingering Unit of Work is left for other tests to pick up.

Hope this helps.
Cheers,

Allard

I think that’s just what I was looking for.

Thanks Allard!
Dave