Testing MassTransit consumer with mediator - c#

I have consumer CarCreatedConsumer which I want to unit test
public class CarCreatedConsumer: IConsumer<CarCreatedEvent>
{
private readonly IMediator _mediator;
public CarCreatedConsumer(IMediator mediator)
{
_mediator = mediator;
}
public async Task Consume(ConsumeContext<CarCreatedEvent> context)
{
....
}
}
Using MassTransit.Testing I'm trying to write test for event consumer
[TestFixture]
public class MyTests
{
private ServiceProvider _provider;
private InMemoryTestHarness _harness;
[SetUp]
public void SetUp()
{
_provider = new ServiceCollection()
.AddMassTransitInMemoryTestHarness(cfg =>
{
cfg.AddConsumer<CarCreatedConsumer>();
}).AddMediator()
.BuildServiceProvider(true);
_harness = _provider.GetRequiredService<InMemoryTestHarness>();
}
[Test]
public async Task MessageShouldBeConsumed()
{
await _harness.Start();
try
{
await _harness.InputQueueSendEndpoint.Send<CarCreatedEvent>(new
{
CarId = Guid.NewGuid.ToString(),
CarOwnerName = "John Stuart"
...
}
// Always false
Assert.True(_harness.Consumed.Select<CarCreatedEvent>().Any());
}
finally
{
await _harness.Stop();
}
}
}
I'm expect this to return true but it fails (returns false). Obviously I'm doing something wrong, any ideas?

Your test harness usage is suspect, and is also using an obsolete version of the configuration. I'd suggest reading the documentation on the current test harness and how to test your consumer.

Related

How to parallelize all the tests in an xunit collection fixture

The Problem
I have a collection fixture in xunit test that lets me group all my tests together to allow for 1) a docker db setup and 2) each test to have their own service collection for activities.
The problem is that the since the tests are all in a collection fixture, the tests classes don't run in parallel. I've tried a few different things in their parallelization docs with no luck. They still run pretty fast but it seems like this would be a big bump in perf that should be doable. Any thoughts here?
The Code
i have a test collection fixture like this
[CollectionDefinition(nameof(TestFixture))]
public class TestFixtureCollection : ICollectionFixture<TestFixture> {}
public class TestFixture : IAsyncLifetime
{
public static IServiceScopeFactory BaseScopeFactory;
public async Task InitializeAsync()
{
// docker db setup
builder.ConfigureServices();
var services = builder.Services;
var provider = services.BuildServiceProvider();
BaseScopeFactory = provider.GetService<IServiceScopeFactory>();
}
public Task DisposeAsync()
{
return Task.CompletedTask;
}
}
public static class ServiceCollectionServiceExtensions
{
public static IServiceCollection ReplaceServiceWithSingletonMock<TService>(this IServiceCollection services)
where TService : class
{
services.RemoveAll(typeof(TService));
services.AddScoped<TService>(_ => Mock.Of<TService>());
return services;
}
}
testing service scope
public class TestingServiceScope
{
private readonly IServiceScope _scope;
public TestingServiceScope()
{
_scope = BaseScopeFactory.CreateScope();
}
public TScopedService GetService<TScopedService>()
{
var service = _scope.ServiceProvider.GetService<TScopedService>();
return service;
}
public async Task<T> ExecuteScopeAsync<T>(Func<IServiceProvider, Task<T>> action)
=> await action(_scope.ServiceProvider);
public Task<T> ExecuteDbContextAsync<T>(Func<CoreDomainDbContext, Task<T>> action)
=> ExecuteScopeAsync(sp => action(sp.GetService<CoreDomainDbContext>()));
public Task<int> InsertAsync<T>(params T[] entities) where T : class
{
return ExecuteDbContextAsync(db =>
{
foreach (var entity in entities)
{
db.Set<T>().Add(entity);
}
return db.SaveChangesAsync();
});
}
}
example test:
[Collection(nameof(TestFixture))]
public class AddRecipeCommandTests
{
[Fact]
public async Task can_add_new_recipe_to_db()
{
// Arrange
var testingServiceScope = new TestingServiceScope();
var fakeRecipeOne = new FakeRecipeForCreationDto().Generate();
// Act
var command = new AddRecipe.Command(fakeRecipeOne);
var recipeReturned = await testingServiceScope.SendAsync(command);
var recipeCreated = await testingServiceScope.ExecuteDbContextAsync(db => db.Recipes
.FirstOrDefaultAsync(r => r.Id == recipeReturned.Id));
// Assert
recipeReturned.Title.Should().Be(fakeRecipeOne.Title);
recipeReturned.Visibility.Should().Be(fakeRecipeOne.Visibility);
recipeReturned.Directions.Should().Be(fakeRecipeOne.Directions);
recipeReturned.Rating.Should().Be(fakeRecipeOne.Rating);
recipeReturned.DateOfOrigin.Should().Be(fakeRecipeOne.DateOfOrigin);
recipeReturned.HaveMadeItMyself.Should().Be(fakeRecipeOne.HaveMadeItMyself);
recipeCreated.Title.Should().Be(fakeRecipeOne.Title);
recipeCreated.Visibility.Should().Be(fakeRecipeOne.Visibility);
recipeCreated.Directions.Should().Be(fakeRecipeOne.Directions);
recipeCreated.Rating.Should().Be(fakeRecipeOne.Rating);
recipeCreated.DateOfOrigin.Should().Be(fakeRecipeOne.DateOfOrigin);
recipeCreated.HaveMadeItMyself.Should().Be(fakeRecipeOne.HaveMadeItMyself);
}
}

MediatR and CQRS testing. How to verify that handler is called?

I am currently trying to implement MediatR in my project covering with tests. I want to cover if handler's Handle is called when sending a request.
I have this query
public class GetUnitsQuery : IRequest<List<UnitResponse>>
{
}
Handler:
public class GetUnitsHandler : IRequestHandler<GetUnitsQuery, List<UnitResponse>>
{
readonly IUnitRepository UnitRepository;
readonly IMapper Mapper;
public GetUnitsHandler(IUnitRepository unitRepository, IMapper mapper)
{
this.UnitRepository = unitRepository;
Mapper = mapper;
}
public async Task<List<UnitResponse>> Handle(GetUnitsQuery request, CancellationToken cancellationToken)
{
return Mapper.Map<List<UnitResponse>>(UnitRepository.GetUnits());
}
}
Send request from the controller:
var result = await Mediator.Send(query);
Any ideas how to test if a Handler is called when specified with a specific Query using MoQ?
Like others said in the comments, you don't need to test the internals of Mediator.
Your test boundary is your application, so assuming a controller along the lines of:
public class MyController : Controller
{
private readonly IMediator _mediator;
public MyController(IMediator mediator)
{
_mediator = mediator;
}
public async IActionResult Index()
{
var query = new GetUnitsQuery();
var result = await Mediator.Send(query);
return Ok(result);
}
}
I would verify Mediator is called like this:
public class MyControllerTests
{
[SetUp]
public void SetUp()
{
_mockMediator = new Mock<IMediator>();
_myController = new MyController(_mockMediator.Object)
}
[Test]
public async void CallsMediator()
{
// Arranged
_mockMediator.SetUp(x=> x.Send(It.IsAny<GetUnitsQuery>()))
.Returns (new List<UnitResponse>());
// Act
await _myController.Index();
// Assert
_mockMediator.Verify(x=> x.Send(It.IsAny<GetUnitsQuery>()), Times.Once);
}
}
I have not used MoQ to check the Received calls to a specific handler. However if I would use Nsubsitute and SpecFlow, I would do something like this in my test.
var handler = ServiceLocator.Current.GetInstance<IRequestHandler<GetUnitsQuery, List<UnitResponse>>>();
handler.Received().Handle(Arg.Any<GetUnitsQuery>(), Arg.Any<CancellationToken>());

Dependency Injection with XUnit Mediatr and IServiceCollection

Currently I'm able to handle IServiceCollection to inject mocks for particular services in the following manner.
public class TestClass
{
private IMediator _mediatr;
private void SetupProvider(IUnitOfWork unitOfWork, ILogger logger)
{
configuration = new ConfigurationBuilder().Build();
_services = new ServiceCollection();
_services.AddSingleton(configuration);
_services.AddScoped(x => unitOfWork);
_services.AddSingleton(logger);
_services.AddMediatR(Assembly.Load("Application"));
_services.AddScoped(typeof(IPipelineBehavior<,>), typeof(LoggerBehaviour<,>));
_mediator = _services.BuildServiceProvider().GetService<IMediator>();
}
[Fact]
public async void UnitTest_Success()
{
var unitOfWork = new Mock<IUnitOfWork>();
var logger = new Mock<ILogger>();
SetupProvider(unitOfWork.Object, logger.Object);
var fixture = new Fixture();
var command = fixture.Create<MediatorCommand>();
unitOfWork.Setup(x => x.Repository.FindAll(It.IsAny<IList<long>>(), It.IsAny<bool?>()))
.ReturnsAsync(new List<Domain.Model>());
var response = await _mediatr.Send(command);
using (new AssertionScope())
{
response.Should().NotBeNull();
response.IsSuccess.Should().BeTrue();
}
}
}
For the following subject under test
public class MediatorCommand : IRequest<CommandResponse>
{
public string Name { get; set ;}
public string Address { get; set; }
}
public class MediatorCommandHandler : IRequestHandler<MediatorCommand, CommandResponse>
{
private readonly ILogger _logger;
private readonly IUnitOfWork _unitOfWork;
public MediatorCommandHandler(IUnitOfWork unitOfWork, ILogger logger)
{
_logger = logger;
_unitOfWork = unitOfWork;
}
public async Task<CommandResponse> Handle(MediatorCommand command, CancellationToken cancellationToken)
{
var result = new CommandResponse { IsSuccess = false };
try
{
var entity = GetEntityFromCommand(command);
await _unitOfWork.Save(entity);
result.IsSuccess = true;
}
catch(Exception ex)
{
_logger.LogError(ex, ex.Message);
}
return result;
}
}
This test runs fine and the unitOfWork and logger mocks are used in the command handlers.
I'm try to move this so that the IServiceCollection construction happens per class instead of each test using the following:
public class SetupFixture : IDisposable
{
public IServiceCollection _services;
public IMediator Mediator { get; private set; }
public Mock<IUnitOfWork> UnitOfWork { get; private set; }
public SetupFixtureBase()
{
UnitOfWork = new Mock<IUnitOfWork>();
configuration = new ConfigurationBuilder().Build();
_services = new ServiceCollection();
_services.AddSingleton(configuration);
_services.AddScoped(x => UnitOfWork);
_services.AddSingleton(new Mock<ILogger>().Object);
_services.AddMediatR(Assembly.Load("Application"));
_services.AddScoped(typeof(IPipelineBehavior<,>), typeof(LoggerBehaviour<,>));
Mediator = _services.BuildServiceProvider().GetService<IMediator>();
}
public void Dispose()
{
Mediator = null;
_services.Clear();
_services = null;
}
}
public class TestClass : IClassFixture<SetupFixture>
{
protected readonly SetupFixture _setupFixture;
public UnitTestBase(SetupFixture setupFixture)
{
_setupFixture = setupFixture;
}
[Fact]
public async void UnitTest_Success()
{
var fixture = new Fixture();
var command = fixture.Create<MediatorCommand>();
_setupFixture.UnitOfWork.Setup(x => x.Repository.FindAll(It.IsAny<IList<long>>(), It.IsAny<bool?>()))
.ReturnsAsync(new List<Domain.Model>());
var response = await _mediatr.Send(command);
using (new AssertionScope())
{
response.Should().NotBeNull();
response.IsSuccess.Should().BeTrue();
}
}
}
Unfortunately with this method my mocks do not get injected on the command handler. Is there a way to get this to work?
Thank you,
I found the issue and it is not related to moving to IClassFixuture<>. The issue was that I was initializing Mediator on a base class an then adding the mock UnitOfWork on a derived class.
This cause the Mediator initialization to fail because one of the beheviours expected the UnitOfWork which at the time was not yet on the container.
Moving the initialization of Mediator after all the services have been added helped me resolve the issue and now all works as expected.
If you try the same thing, please make sure to include all the services in the container before initializing any objects that require those dependencies.
Thank you all those who had input.

I want to Create Xunit test for this controller. How can i do that

I have created small kind of xunit test case but I don't know how to create this controller which i have mention below.
public class PropertyController : ControllerBase
{
private readonly IMediator _mediator;
private readonly ILogger<PropertyController> _logger;
public PropertyController(IMediator mediator, ILogger<PropertyController> logger)
{
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public async Task<IActionResult> AddProperty([FromBody] AddPropertyCommand command)
{
bool commandResult = false;
_logger.LogInformation(
"----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({#Command})",
command.GetGenericTypeName(),
nameof(command.ModifiedUserId),
command.ModifiedUserId,
command);
commandResult = await _mediator.Send(command);
if (!commandResult)
{
return BadRequest();
}
return Ok();
}
I have created like this. i have mock the dependency and create a test case for add command is working fine or not
public class PropertyControllerTest
{
private readonly PropertyController _it;
private readonly Mock<IMediator> _mediatorMock;
private readonly Mock<ILogger<PropertyController>> _loggerPropertycontrollerMock;
public PropertyControllerTest()
{
_mediatorMock = new Mock<IMediator>();
_loggerPropertycontrollerMock = new Mock<ILogger<PropertyController>>();
_it = new PropertyController(_mediatorMock.Object, _loggerPropertycontrollerMock.Object);
}
[Fact]
public void it_Should_add_information_successfully_and_returns_200_status_result()
{
//How can i write xunit test case. I'm creating like this
_mediatorMock.Setup(x => x.Send().Returns(property);
}
The test below covers the 200 status result - a similar test for bad requests would be very similar.
[Fact]
public void it_Should_add_information_successfully_and_returns_200_status_result()
{
// Arrange
var expected = new AddPropertyCommand();
_mediatorMock.Setup(x => x.Send(It.IsAny<AddPropertyCommand>())).Returns(true);
// Act
var actionResult = _it.AddProperty(expected);
// Assert
actionResult.ShouldBeAssignableTo<OkResult>();
_mediatorMock.Verify(x => x.Send(expected));
}
N.B. actionResult.ShouldBeAssignableTo<OkResult>(); is written using the Shouldly assertion framework, you can swap that out for anything you like. The one built into XUnit would be like this: Assert.IsType(typeof(OkResult), actionResult);

Unit testing an async method with Task<bool> return type

I need to create a unit test for the following class's InvokeAsync method. What it merely does is calling a private method in the same class which includes complex logical branches and web service calls. But the unit test are written only for the public methods. So what should I do in this scenario? What should I test in here? Any suggestions would be greatly appreciated.
public class MyCustomHandler
{
private readonly ILogger _logger;
private readonly HttpClient _httpClient;
public MyCustomHandler(HttpClient client, ILogger logger)
{
_httpClient = httpClient;
_logger = logger;
}
public override async Task<bool> InvokeAsync()
{
return await InvokeReplyPathAsync();
}
private async Task<bool> InvokeReplyPathAsync()
{
// Lot of code with complex logical branches and calling web services.
}
}
If your testing framework supports it (MsTest does) you can declare your test method async and call the method from there. I'd mock the web services using a mock framework such as Rhino Mocks so you don't need to depend on the actual web service.
public interface IWebService
{
Task<bool> GetDataAsync();
}
[TestClass]
public class AsyncTests
{
[TestMethod]
public async void Test()
{
var webService = MockRepository.GenerateStub<IWebService>();
webService.Expect(x => x.GetDataAsync()).Return(new Task<bool>(() => false));
var myHandler = new MyCustomHandler(webService);
bool result = await myHandler.InvokeAsync();
Assert.IsFalse(result);
}
}
[TestMethod]
public async void TestWebServiceException()
{
var webService = MockRepository.GenerateStub<IWebService>();
webService.Expect(x => x.GetDataAsync()).Throw(new WebException("Service unavailable"));
var myHandler = new MyCustomHandler(webService);
bool result = await myHandler.InvokeAsync();
Assert.IsFalse(result);
}

Categories

Resources