I am fairly new to programming and only know the basics.
I am currently writing a unit test for a .net core 2.2 controller. I am using Rider, Nunit, and Moq.
Here is one of the unit test where I am getting a problem:
[Test]
[TestCase(true)]
[TestCase(false)]
public async Task GetPersonAsync_PersonDoesExist_ReturnOk(bool includeRelated)
{
_repository.Setup(r => r.GetPersonAsync(_id, includeRelated)).ReturnsAsync(_person);
_mapper.Setup(m => m.Map<Person, GetPersonResource>(It.IsAny<Person>())).Returns(_getPersonResource);
var result = await _controller.GetPersonAsync(_id);
Assert.That(result, Is.TypeOf<OkObjectResult>());
}
Here is my constructor/top part and setup of that unit test:
public class PersonsControllerTests
{
private Mock<IMapper> _mapper;
private Mock<IUnitOfWork> _unitOfWork;
private Mock<IClientsRepository> _repository;
private PersonsController _controller;
private int _id;
private Person _person;
private GetPersonResource _getPersonResource;
private CreatePersonResource _createPersonResource;
private UpdatePersonResource _updatePersonResource;
[SetUp]
public void Setup()
{
_mapper = new Mock<IMapper>();
_unitOfWork = new Mock<IUnitOfWork>();
_repository = new Mock<IClientsRepository>();
_controller = new PersonsController(_mapper.Object, _repository.Object, _unitOfWork.Object);
_id = 1;
_person = new Person {Id = 1};
_getPersonResource = new GetPersonResource {Id = 1};
_createPersonResource = new CreatePersonResource {Code = "a"};
_updatePersonResource = new UpdatePersonResource {Code = "a"};
}
Here is my GetPersonAsync method in my controller:
[HttpGet("{id}")]
public async Task<IActionResult> GetPersonAsync(int id)
{
var person = await repository.GetPersonAsync(id);
if (person == null)
return NotFound();
return Ok(mapper.Map<Person, GetPersonResource>(person));
}
Here is my constructor/top part for my controller:
[Route("/api/persons")]
public class PersonsController : Controller
{
public IMapper mapper { get; }
private readonly IClientsRepository repository;
private readonly IUnitOfWork unitOfWork;
public PersonsController(IMapper mapper, IClientsRepository repository, IUnitOfWork unitOfWork)
{
this.unitOfWork = unitOfWork;
this.repository = repository;
this.mapper = mapper;
}
Here is my GetPersonAsync method in my Repository:
public async Task<Person> GetPersonAsync(int id, bool includeRelated = true)
{
if (!includeRelated)
return await context.Persons
.FirstOrDefaultAsync(p => p.Id == id);
else
return await context.Persons
.Include(p => p.Clients)
.Include(p => p.ClientRelateds)
.ThenInclude(cr => cr.ClientRelationType)
.FirstOrDefaultAsync(p => p.Id == id);
}
Here is my GetPersonAsync signature in my IRepository:
Task<Person> GetPersonAsync(int id, bool includeRelated = true);
The problem that I am encountering is that whenever I run a test and change the includeRelated argument to false, which is true by default, my tests fail.
For example, in the test that I have given above my test with test case false, it should return Ok but is returning NotFound, when I use the true test case it returns Ok and passes which is what I want. I also get the same when I want to see if a model is saved. My test where includeRelated is set to true invokes my _unitOfWork.CompleteAsync method but does not invoke it when includeRelated is set to false.
When I set the default value of include related to false in my repository all my test cases with includeRelated true fails and includeRelated false passes.
There is a big chance that I either made a mistake in my project or in my unit test but it seems to me like, and correct me if I'm wrong, there is a bug with Moq as I am Mocking the repository and the actual implementation of the repository (i.e the default value of true for includeRelated) does not matter at all.