NServiceBus.Testing: How to test sagas that need an instance of IBus injected?

97 views
Skip to first unread message

Manuel Pallier

unread,
Sep 22, 2016, 1:28:59 AM9/22/16
to Particular Software
Helpful information to include
Product name:  NServiceBus.Testing
Version: 5.2.1
Stacktrace: -
Description:

Let's say I have a saga that gets some services injected in its constructor. One or multiple of those services require an IBus injected in their constructors. How to I correctly test this saga?
For simple message handlers there is the Test.Handler overload that provides an IBus and allows the contruction of the handler with that bus. That allows me to create the handler with the container of my choice and pass the test bus as an dependency override. But it seems like there is no such overload for Test.Saga? I know that the Saga class has a Bus property that provides the test IBus instance, but that doesn't help me to get that bus injected in my services, right?

What I'm trying to test is that when a specific Handle method is called on my saga, an event should be published. But the event isn't published directly by the saga, instead this is done by one of the services that is injected into the saga.

Daniel Marbach

unread,
Sep 22, 2016, 3:02:22 AM9/22/16
to Particular Software
Hi Manuel

Do I understand it correctly that you are pushing IBus into the services which are called by the saga and does services decide to publish messages themselves? Mind if I ask why you are doing that? In essence, you are coupling the service business logic to the messaging concern. If you'd redesign your services in a way so that the service takes a pure business decision and returns that business decision to the saga and then the saga decides whether messages will be published or not you'd have a better separation of concerns and the bus would not be leaking into your business / domain logic. Similar to hexagonal architecture or onion architecture I'd go for a core domain which is persistence and "bus" free.

But now back to your question. The current test saga design assumes that your dependencies should be set as properties. You could use

WithExternalDependencies(saga => saga.Dependency = new ServiceStub(Test.Bus));

would that help?

Daniel

Manuel Pallier

unread,
Sep 22, 2016, 3:32:37 AM9/22/16
to Particular Software
Hi,

I'm developing a CQRS+ES system and my use case is as follows:
The saga handles an event that was saved in the event store. Based on this event the saga updates a different aggregate. To do this the saga needs a service that loads and saves aggregates. This service then uses an event store service to save the domain event in the event store database. The event store service publishes the event after storing it, which is done via the IBus (via a small wrapper service so that the event store doesn't need a reference to NServiceBus).

Is there an way to better design this architecture?

WithExternalDependencies() works, thanks. But it requires the saga to provide a service property with a public (or at least internal when used with InternalsVisibleTo) setter. So I assume there is no way to do this without this property?

Daniel Marbach

unread,
Sep 26, 2016, 3:57:18 AM9/26/16
to Particular Software
Hi

> WithExternalDependencies() works, thanks. But it requires the saga to provide a service property with a public (or at least internal when used with InternalsVisibleTo) setter. So I assume there is no way to do this without this property?

Unfortunately this is the only way right now if you use Test.Saga<TSaga>. But you could also use

Test.Saga<TSaga>(TSaga saga) overload where you pass in an already created instance of a saga. That overload has the drawback that you have to assign the data property of the saga yourself.

Does that help?

Daniel

Manuel Pallier

unread,
Sep 26, 2016, 5:29:14 AM9/26/16
to Particular Software
The overload that takes a saga instance doesn't work for me since my saga indirectly requires a IBus instance, and that is only created by the Test.Saga method itself.
Best would be an creation function overload like the Test.Handle method provides, but the WithExternalDependencies solution is ok too.
Reply all
Reply to author
Forward
0 new messages