I am trying to unit test my controller but I am using MediatR. I have mocked it but somehow result is null. I tried to search other people questions but non of them helped.
My controller:
[HttpGet("{authorId}")]
[ProducesResponseType(200, Type = typeof(Author))]
[ProducesResponseType(400)]
public async Task<IActionResult> GetAuthor(int authorId)
{
var query = new GetAuthorQuery(authorId);
var result = await _mediator.Send(query);
return result != null ? (IActionResult)Ok(result) : NotFound();
}
Unit Test constructor:
private Mock<IMediator> _mediator;
public BookStoreAuthorControllerTests()
{
_mediator= new Mock<IMediator>();
_authorRepository= new Mock<IAuthorRepository>();
fixture= new Fixture();
fixture.Behaviors.OfType<ThrowingRecursionBehavior>().ToList()
.ForEach(b => fixture.Behaviors.Remove(b));
fixture.Behaviors.Add(new OmitOnRecursionBehavior());
var mapperConfig = new MapperConfiguration(c =>
{
c.AddProfile<Helpers.MappingProfiles>();
});
_mapper = mapperConfig.CreateMapper();
}
GetAuthor Test :
[Test]
public async Task GetAuthor_Returns_Ok()
{
var author = fixture.Build<Author>().Create();
var mappedAuthor= _mapper.Map<AuthorDto>(author);
var controller = new AuthorController(_mediator.Object);
var query = new GetAuthorQuery(author.Id);
_authorRepository.Setup(r=>r.GetAuthor(author.Id)).ReturnsAsync(author);
_mediator.Setup(x => x.Send(query, It.IsAny<CancellationToken>())).ReturnsAsync(mappedAuthor);
var result = await controller.GetAuthor(author.Id);
var obj = result as ObjectResult;
Assert.AreEqual(200, obj.StatusCode);
}
The issue is in the mocking of that Send
method, shown below.
_mediator.Setup(
x => x.Send(query, It.IsAny<CancellationToken>())
).ReturnsAsync(mappedAuthor);
Given that the query
variable is a GetAuthorQuery
class
/reference type, makes that is not the exact same instance that gets passed at runtime. Because of that, the mock doesn't execute the ReturnsAsync
method in order to return the given Author
object.
2 possible ways to solve this; do one of below.
It.IsAny<GetAuthorQuery>()
instead of query
._mediator.Setup(
x => x.Send(It.IsAny<GetAuthorQuery>(), It.IsAny<CancellationToken>())
).ReturnsAsync(mappedAuthor);
GetAuthorQuery
as a record
instead of a class
; record
types use value equality. Doing so you can keep using that query
variable in your mock setuppublic record GetAuthorQuery : IRequest<Author>