我是单元测试新手,正在尝试为我的 Web API Controller 的 POST
创建一些 Xunit 测试方法。
这是我的 Controller 的 POST
方法:
[HttpPost("")]
public async Task<IActionResult> CreateArea([FromBody] AreaForCreationDto area)
{
// Check that the 'area' object parameter can be de-serialised to a AreaForCreationDto.
if (area == null)
{
var message = "Could not de-serialise the request body to an AreaForCreationDto object";
_logger.LogError(message);
// Return an error 400.
return BadRequest(message);
}
/*
* ModelState.IsValid is determined by the attributes associated with the
* Data Annotations on the properties of the ViewModel.
*/
if (!ModelState.IsValid)
{
// Return a response with a Status Code 422.
return new UnprocessableEntityObjectResult(ModelState);
};
// Map a AreaForCreationDto object to a Area entity.
var areaEntityToAdd = _mapper.Map<Area>(area);
// Call the repository to add the new Area entity to the DbContext.
_areaRepository.AddArea(areaEntityToAdd);
// Save the new Area entity, added to the DbContext, to the SQL database.
if (await _areaRepository.SaveChangesAsync())
{
// Note: AutoMapper maps the values of the properties from the areaEntityToAdd
// to a new areaToReturn object.
// This ensures that we don't expose our Area entity to the web browser.
var areaToReturn = _mapper.Map<AreaDto>(areaEntityToAdd);
// Return a 201 'created' response along with the location URL in the
// response Header.
return CreatedAtRoute("GetArea",
new { id = areaToReturn.Id },
areaToReturn);
}
else {
// The save failed.
var message = $"Could not save new Area {areaEntityToAdd.Id} to the database.";
_logger.LogWarning(message);
throw new Exception(message);
};
}
我编写的第一个单元测试旨在确保在发送 POST 请求时,对象可以反序列化为 AreaForCreation
对象,该函数返回 201 CreatedAtRouteResult
以及已创建的新区域。
这是 Xunit 测试:
[Fact]
public void ReturnAreaForCreateArea()
{
//Arrange
var _mockAreaRepository = new Mock<IAreaRepository>();
_mockAreaRepository
.Setup(x => x.AddArea(testArea));
var _mockMapper = new Mock<IMapper>();
_mockMapper
.Setup(_ => _.Map<Area>(It.IsAny<AreaForCreationDto>()))
.Returns(testArea);
var _mockLogger = new Mock<ILogger<AreasController>>();
var _sut = new AreasController(_mockAreaRepository.Object, _mockLogger.Object, _mockMapper.Object);
// Act
var result = _sut.CreateArea(testAreaForCreationDto);
// Assert
Assert.NotNull(result);
var objectResult = Assert.IsType<CreatedAtRouteResult>(result);
var model = Assert.IsAssignableFrom<AreaDto>(objectResult.Value);
var areaDescription = model.Description;
Assert.Equal("Test Area For Creation", areaDescription);
}
当单元测试尝试 Assert.IsType<CreatedAtRouteResult>(result)
时,我抛出异常。调试显示 Controller 无法保存到存储库。我的AreaRepository
有以下 AddArea 函数,它不返回值,所以我假设我的 _mockAreaRepository
不需要Return
条件集(这里可能是错误的)。
我需要配置我的 mockAreasRepository
调用SaveChangesAsync()
的结果?
最佳答案
是的,因为它是异步的,您需要模拟已完成任务的返回以允许该方法
await _areaRepository.SaveChangesAsync()
能够继续。
您还需要通过返回任务
并等待被测方法来将测试更新为异步。
[Fact]
public async Task ReturnAreaForCreateArea() { //<-- note test is now async as well
//Arrange
var _mockAreaRepository = new Mock<IAreaRepository>();
_mockAreaRepository
.Setup(x => x.AddArea(testArea));
_mockAreaRepository
.Setup(x => x.SaveChangesAsync())
.ReturnsAsync(true); //<-- returns completed Task<bool> when invoked
var _mockMapper = new Mock<IMapper>();
_mockMapper
.Setup(_ => _.Map<Area>(It.IsAny<AreaForCreationDto>()))
.Returns(testArea);
_mockMapper
.Setup(_ => _.Map<AreaDto>(It.IsAny<Area>()))
.Returns(testAreaDto);
var _mockLogger = new Mock<ILogger<AreasController>>();
var _sut = new AreasController(_mockAreaRepository.Object, _mockLogger.Object, _mockMapper.Object);
// Act
var result = await _sut.CreateArea(testAreaForCreationDto);//<-- await
// Assert
Assert.NotNull(result);
var objectResult = Assert.IsType<CreatedAtRouteResult>(result);
var model = Assert.IsAssignableFrom<AreaDto>(objectResult.Value);
var areaDescription = model.Description;
Assert.Equal("Test Area For Creation", areaDescription);
}
关于asp.net-mvc - ASP.Net Web API Controller 单元测试 POST,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48426628/