Reputation: 41
So I am very new to writing tests. I created an ASP.NET core web api along with angular. I have to write unit tests for the web API controllers. I have been reading Microsoft documentation on how to get started with unit tests of ASP.NET web APIs. But I am still very unsure on how to go about writing proper tests.
My Controller Code
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class OrdersController : ControllerBase
{
private readonly IOrderRepository _repo;
private readonly IMapper _mapper;
public OrdersController(IOrderRepository repo, IMapper mapper)
{
_repo = repo;
_mapper = mapper;
}
[AllowAnonymous]
[HttpPost()]
public async Task<IActionResult> AddOrder(OrderForMappingDto orderForMappingDto)
{
//if(orderForMappingDto.ARentalOrNot == null)
//{
// throw new Exception("Value can't be left null");
//}
var orderToCreate = _mapper.Map<TblOrder>(orderForMappingDto);
var createdOrder = await _repo.AddOrder(orderToCreate);
return Ok(createdOrder);
}
}
My Repository Code
public class OrderRepository : IOrderRepository
{
private readonly MovieRentalDBContext _context;
public OrderRepository(MovieRentalDBContext context)
{
_context = context;
}
public async Task<TblOrder> AddOrder(TblOrder tblOrder)
{
await _context.TblOrder.AddAsync(tblOrder);
await _context.SaveChangesAsync();
return tblOrder;
}
}
I understand there is a lot of mocking to be done. But do I need to mock the Entity Framework as well? I wrote a simple test file.
public void PostsAorder_WhenCalled_ReturnsOkWithResponse()
{
var mockOrderRepository = new Mock<IOrderRepository>();
var mockOrderMapper = new Mock<IMapper>();
var orderControllerObject = new OrdersController(mockOrderRepository.Object, mockOrderMapper.Object);
Task<IActionResult> contentResult = orderControllerObject.AddOrder(new OrderForMappingDto
{
ACustomerId = 3,
AMovieId = 18,
ARentalOrNot = false,
AOrderedDate = DateTime.Now
}) ;
//var contentResult = actionResult as OkNegotiatedContentResult<OrderForMappingDto>;
Assert.IsNotNull(contentResult);
Assert.IsNotNull(contentResult.Result);
}
The OkNegotioatedContent function doesn't work with Tasks. How do I go about using that for task. Also, the tests is passing even when I don't supply the last 3 arguments even though in the DTO they are classified as [Required]
. Can somebody help on how to modify the test properly.
mapper Configuration-
Upvotes: 1
Views: 3159
Reputation: 22679
Your test is almost okay. First the fixed version then some explanation:
[Fact]
public async Task GivenAValidOrder_WhenICallTheAsOrder_ThenItReturnsOkWithResponse()
{
//Arrange
var mockOrderMapper = new Mock<IMapper>();
mockOrderMapper.Setup(mapper => mapper.Map<TblOrder>(It.IsAny<OrderForMappingDto>()))
.Returns(new TblOrder());
var mockOrderRepository = new Mock<IOrderRepository>();
mockOrderRepository.Setup(repo => repo.AddOrder(It.IsAny<TblOrder>()))
.ReturnsAsync((TblOrder order) => order);
var SUT = new OrdersController(mockOrderRepository.Object, mockOrderMapper.Object);
//Act
var contentResult = await SUT.AddOrder(new OrderForMappingDto
{
ACustomerId = 3,
AMovieId = 18,
ARentalOrNot = false,
AOrderedDate = DateTime.Now
});
//Assert
Assert.NotNull(contentResult);
Assert.IsAssignableFrom<OkObjectResult>(contentResult);
var result = ((OkObjectResult)contentResult).Value;
Assert.NotNull(result);
Assert.IsAssignableFrom<TblOrder>(result);
}
await
the controller's action to finish in order to examine its result.Arrange Act Assert
comments to the code in order to emphasize which phase starts when.TblOrder
and the repo mock to return whatever it receives.orderControllerObject
to SUT
, because it emphasize which component is under examination (System Under Test).IsAssingableForm
instead of IsType
because it checks against derived classes as well. In this particular case it is not mandatory, but it is a good practice.OkObjectResult
not OkNegotiatedContentResult
, so you should check against that.Upvotes: 4