asp.net-mvc - ASP.Net Web API Controller 单元测试 POST

标签 asp.net-mvc unit-testing moq xunit

我是单元测试新手,正在尝试为我的 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/

相关文章:

c# - ASP MVC 中的自定义角色提供程序

asp.net-mvc - 奇怪的 asp.net mvc 错误

java - 使用 powermockito 验证静态 void 方法的调用

unit-testing - Istanbul 尔纽约市排除测试文件

c# - 无法序列化接口(interface) System.Linq.IQueryable

asp.net-mvc - 带有资源文件的模型的单选按钮枚举助手

java - Spring junit测试错误 "could not find current request via RequestContextHolder"

unit-testing - Autofixture 和 WebApi Controller

entity-framework - 模拟 Entity Framework 内连接

c# - 最小起订量文档在哪里?