【问题标题】:ASP.Net Web API Controller Unit Test FailsASP.Net Web API 控制器单元测试失败
【发布时间】:2018-01-19 15:42:10
【问题描述】:

我创建了一个比较简单的Controller如下:

[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");
            }

        }
...

我是单元测试的新手,正在努力让最基本的测试正常工作。我在 Visual Studio 2017 中使用 XUnit 和 Moq。

为了让我的脚趾浸入水中,我想测试控制器上的 GetAreas 方法是否会返回一个 okObjectResult,但它没有!

这是我的测试:

[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;
        }

如果您需要任何存储库或实体详细信息,请告诉我。我预计问题出在我对设置模拟对象的误解中,无论哪种方式我都看不到。

【问题讨论】:

  • 调试并检查实际返回的类型。然后您可以查看是否检查了错误的类型。抛出可能的错误并返回错误的请求。
  • 我得到了一个 BadRequest 对象和一个 StatusCode 400
  • @TDC 你应该注入 IMapper 以便能够模拟它。
  • 不管怎样,您应该避免在单个 try...catch 块中包装大量代码,尤其是在捕获像Exception 这样通用的东西时。它并不能真正帮助您找到问题,因为实际上任何东西都可能引发某种异常。捕获离散单元(即 try..catch 存储库访问,然后 try..catch 映射)或显式捕获和处理异常类型。
  • 另外,一般来说,你永远不应该捕获Exception,除非你在catch块中将它与throw;结合起来,即重新抛出异常(通常只是为了记录目的而完成)。只应吞下特定的例外情况。

标签: c# unit-testing moq xunit asp.net-core-webapi


【解决方案1】:

调试并检查实际返回的类型。然后您可以查看是否检查了错误的类型。可能会抛出错误并返回错误的请求。

另一种确保在测试中的方法

// Act
var result = _sut.GetAreas() as OkObjectResult;

//Assert
Assert.NotNull(result);

如果使用 Automapper,那么我还建议将 IMapper 注入控制器,以便在测试时也能够模拟它,以避免只为测试而设置它。与静态依赖项紧密耦合可能会对代码的可测试性产生不良影响。

[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");
        }
    }
    //...
}

只需确保将抽象与其在组合根中的实现相关联。

services.AddAutoMapper(assembly1, assembly2 /*, ...*/);

参考AutoMapper extensions for Microsoft.Extensions.DependencyInjection

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-14
    • 2021-01-24
    • 2015-11-07
    • 1970-01-01
    • 2012-09-04
    • 1970-01-01
    • 2017-06-02
    相关资源
    最近更新 更多