Reputation: 1929
I have created a relatively simple Controller as follows:
[Route("api/areas")]
public class AreasController : Controller
{
private IAreaRepository _areaRepository;
private ILogger<AreasController> _logger;
// Constructor.
public AreasController(
IAreaRepository areaRepository,
ILogger<AreasController> logger
)
{
_areaRepository = areaRepository;
_logger = logger;
}
[HttpGet()]
public IActionResult GetAreas()
{
try
{
_logger.LogTrace("AreasController.GetAreas called.");
// Create an IEnumerable of Area objects by calling the repository.
var areasFromRepo = _areaRepository.GetAreas();
var areas = Mapper.Map<IEnumerable<AreaDto>>(areasFromRepo);
// Return a code 200 'OK' along with an IEnumerable of AreaDto objects mapped from the Area entities.
return Ok(areas);
}
catch (Exception ex)
{
_logger.LogError($"Failed to get all Areas: {ex}");
return BadRequest("Error Occurred");
}
}
...
I am new to Unit Testing and am struggling to get the most basic of tests working. I am using XUnit and Moq in Visual Studio 2017.
To dip my toe in the water I wanted to test that the GetAreas method on the controller, if there were some Areas, would return an okObjectResult, but it doesn't!
Here's my test:
[Fact]
public void ReturnAreasForGetAreas()
{
//Arrange
var area = new Area
{
Id = new Guid("761317f6-f9d7-4fa4-a8fe-c6179daee3da"),
Description = "Test Area",
SortIndex = 1
};
var _mockAreaRepository = new Mock<IAreaRepository>();
_mockAreaRepository
.Setup(x => x.GetAreas())
.Returns(new List<Area> { area });
var _mockLogger = new Mock<ILogger<AreasController>>();
var _sut = new AreasController(_mockAreaRepository.Object, _mockLogger.Object);
// Act
var result = _sut.GetAreas();
Assert.NotNull(result);
// Assert
var okResult = result.Should().BeOfType<OkObjectResult>().Subject;
}
Let me know if you want any Repository or Entity details. I am expecting the problem to be in my misunderstanding of setting up the mocked objects, either way I can't see it.
Upvotes: 2
Views: 1352
Reputation: 247531
Debug and check what type is actually being return. Then you can see if you are checking for the wrong type. It is possible an error is being thrown and the bad request is being returned.
another way to ensure that in the test
// Act
var result = _sut.GetAreas() as OkObjectResult;
//Assert
Assert.NotNull(result);
If using Automapper then I would also advise injecting the IMapper
into the controller to be able to mock that as well when testing to avoid having to set it up just for tests. Tightly coupling to static dependencies can have undesired effects on the testability of your code.
[Route("api/areas")]
public class AreasController : Controller {
private IAreaRepository _areaRepository;
private ILogger<AreasController> _logger;
private IMapper mapper;
// Constructor.
public AreasController(
IAreaRepository areaRepository,
ILogger<AreasController> logger,
IMapper mapper
) {
_areaRepository = areaRepository;
_logger = logger;
this.mapper = mapper;
}
[HttpGet()]
public IActionResult GetAreas() {
try {
_logger.LogTrace("AreasController.GetAreas called.");
// Create an IEnumerable of Area objects by calling the repository.
var areasFromRepo = _areaRepository.GetAreas();
var areas = mapper.Map<IEnumerable<AreaDto>>(areasFromRepo);
// Return a code 200 'OK' along with an IEnumerable of AreaDto objects mapped from the Area entities.
return Ok(areas);
} catch (Exception ex) {
_logger.LogError($"Failed to get all Areas: {ex}");
return BadRequest("Error Occurred");
}
}
//...
}
just make sure to associate the abstraction with its implementation at the composition root.
services.AddAutoMapper(assembly1, assembly2 /*, ...*/);
Reference AutoMapper extensions for Microsoft.Extensions.DependencyInjection
Upvotes: 1