Closed ianbattersby closed 9 years ago
@ianbattersby What probably fixes this is to Moq multiple interfaces with .As
We also have a testing framework to test handlers and sagas. http://docs.particular.net/nservicebus/unit-testing
The second option requires all your current tests to be converted. It is probably best to test your handlers and sagas this way as it forces you to test in small units of execution so you can really do isolated behavioral testing.
Let me know if this resolves your problem.
@ramonsmits Erm, thanks for the suggestion but I don't think As<>()
is going to help in this scenario, you can only add interfaces with As<>()
and not concrete types such as UnicastBus
(which seems to have no unifying interface).
Testing the handler using this vanilla-style is the ultimate isolation IMHO - especially breaking down tests to cover deeper execution (e.g. verifying a factory method has been called with expected arguments). I appreciate this may be too deep for some but we occasionally do this. The testing library looks good at testing a scenario of a saga (something we normally cover in Acceptance Tests) but adds an additional layer of abstraction that if we don't need I'd rather not use. Also, conversion to the testing library would be huge in our 7+ repositories.
I'm not sure of a way round this without implementing IUnicastBus
interface unifying IStartableBus
, IInMemoryOperations
, and IManageMessageHeaders
? Even if the testing library would be your preferred usage I would see the inability to unit-test sagas/handlers in a vanilla form a limitation.
@ianbattersby Did you try the .As<IManageMessageHeaders>
because the screenshot that you added clearly shows that an exception is raised because the given bus does not implement IManageMessageHeaders
. Adding this interface should result in a fake IManageMessageHeaders
and not throw the InvalidOperationException
.
As you are unittesting you probably only want to use fakes on the your current unittests.
Also, from my personal experience in unittesting handlers is that you can easily use Moq for testing behavior based on a incoming message to see how it interacts with its dependencies like repositories, specifications, calculations, etc. Just use a fake IBus
implementation.
You want to use the NServiceBus.Testing framework when you want to validate a handlers behavior in regards to its injected IBus
. The reason for that is that there are multiple methods to send or publish a message. The testing framework makes it more easy to just test if a message is published or send without knowing which method is called. This makes these test less fragile when you refactor a handler where its behavior stays the same but using a different implementation.
@ramonsmits After some experimenting seems my confusion stems from var myMock = new Mock<IBus>().As<IManageMessageHeaders>();
resulting in a Type of Mock<IManageMessageHeaders>
whereas doing var myMock = new Mock<IBus>(); myMock.As<IManageMessageHeaders>()
keeps the Type intact as IBus
. Huzzah!
So I now have this working using;
this.bus = new Mock<IBus>();
this.bus.As<IManageMessageHeaders>().Setup(m => m.SetHeaderAction).Returns((o, s, v) => { });
Noted your comment about faking out IBus opposed to mocking, we do have a fake IBus originating from @danielmarbach but many codebases still use Moq. Also appreciate benefits and lack of brittleness of using NServiceBus.Testing, I suspect if we didn't have full acceptance tests we'd undoubtedly have followed this route.
Thanks for the help!
NB: Working against 'develop' branch
We are currently upgrading from v4 to v5 and have some unit tests that use Moq to pass in a
Mock<IBus>
. All tests pass apart from those setting timeouts where the exception "bus does not implement IManageMessageHeaders" is thrown:Looking at the source I can see
IManageMessageHeaders
is only implemented againstUnicastBus
(notIBus
) , so suspect I'm missing something, or should be perhaps using a testing support library for this mock? Guidance much appreciated.