I want to unit test services which uses Masstransit(rmq) to send messages. According to the doc, there is InMemoryTestHarness class for this. But I can't figure out how can I use it in my scenario.
I use AbpBoilerplate framework, so first of all I need to register Masstransit within Castle Windsor. For test module I do it smth like this:
var harness = new InMemoryTestHarness();
harness.Start().Wait(TimeSpan.FromSeconds(1));//harness.Bus is not null now
IocManager.IocContainer.Register(Component.For<InMemoryTestHarness>().Instance(harness));
IocManager.IocContainer.Register(Component.For<IBus, IBusControl>().Instance(harness.Bus));
Service I want to test is following:
public class ProcessingService
{
private readonly ProjectService _projectService;
//NOTE previously there was IBus interface...
private readonly ISendEndpointProvider _provider;
public ProcessingService(ISendEndpointProvider provider, [NotNull] ProjectService projectService )
{
_ProjectService = ProjectService ?? throw new ArgumentNullException(nameof(ProjectService));
_provider = provider;
}
public async Task ProcessFileAsync([NotNull] fileInput FileInput,
[NotNull] IUserProcessingSettings userProcessingSettings)
{
if (fileInput == null) throw new ArgumentNullException(nameof(fileInput));
if (userProcessingSettings == null) throw new ArgumentNullException(nameof(userProcessingSettings));
var entity = await _projectService.GetSomeEntityAsync();
ProcessFileCommand msg = new ProcessFileCommand(entity);
await _provider.Send(msg).ConfigureAwait(false);
}
}
The first problem with code above is that for now if I use ISendEndpointProvider instead of IBus as suggeted in the doc it is simply cannot resolve dependecies, no ISendEndpointProvider registered. And I'm not quite understand how to handle it within InMemoryTestHarness abstraction...
Here is the test method and consumer class:
[Fact]
public async Task Simple_Masstranist_Consumer_Test1()
{
//it was injected and started in ABP test module
var harness = Resolve<InMemoryTestHarness>();
//NOTE which one is correct option -- handler or consumer?
var consumerHarness = harness.Consumer<MyConsumer>();
// await harness.SubscribeHandler<MyConsumer>().ConfigureAwait(false);
try
{
var processingService = Resolve<ProcessingService>();
var emptyFileImput = FileInput.EmptyFileInput(1);
await ProcessingService.ProcessFileAsync(emptyFileImput).ConfigureAwait(false);
//NOTE test hangs on this command
consumerHarness.Consumed.Select<ProcessFileCommand>().Any().ShouldBeTrue();
// the consumer publish the event
harness.Published.Select<ProcessFileCommand>().Any().ShouldBeTrue();
}
finally
{
//already started...
await harness.Stop().ConfigureAwait(false);
}
}
public class MyConsumer : IConsumer<ProcessFileCommand>
{
public Task Consume(ConsumeContext<ProcessFileCommand> context)
{
context.Message.ShouldNotBeNull();
context.Message.EntityId.ShouldBe(1);
context.Message.FilePath.ShouldBe("some_path");
return Task.FromResult(true);
}
}
My expectations for InMemoryTestHarness is that it is a wrapper of InMemory bus suitable for tests, so when my service send some message, I expect that it would be reflected in proper structures of InMemoryTestHarness. When I've used IBus instead of ISendEndpointProvider test code simply hang on consumerHarness.Consumed.Select().Any().ShouldBeTrue(); line of code. It seems that it blocks for some event which will neven occur.
So, my questions are:
- Is it correct to use InMemoryTestHarness to mock message queue in my scenario, maybe I should configure manually InMemoryBus for that?
2)If I want to use ISendEndpointProvider within DI, what should I register?
Thanks in advance
Update:
var testHarness = new InMemoryTestHarness();
IocManager.IocContainer.Register(Component.For<InMemoryTestHarness>().UsingFactoryMethod(kernel =>
{
var busRegistrationContext = kernel.Resolve<IRegistration>();
testHarness.OnConfigureInMemoryBus +=
configurator => configurator.ConfigureEndpoints(busRegistrationContext);
return testHarness;
}).LifestyleSingleton());