【问题标题】:WebApi action method returning nullWebApi 操作方法返回 null
【发布时间】:2020-01-12 06:19:15
【问题描述】:

已经一整天了,我无法找到解决方案。 从 PostMan 调用时,我的 Controller 的 ActionMethod 工作正常。 但是当我从我的单元测试方法中调用它时,它一直返回 null。

这是我的代码。 我已经在 StackOverflow 上找到了答案: https://stackoverflow.com/a/56498657/11425180
但这并不能解决我的问题。

这是我的操作方法

[HttpPost("register")]
        public async Task<IActionResult> RegisterUser([FromBody] CreateUserRequest request)
        {
            if (!ModelState.IsValid)
                return BadRequest(ModelState);
            try
            {
                //  Map request with dto and give to service
                CreateUserRequestDto createDto = _mapper.Map<CreateUserRequestDto>(request);
                CreateUserResponseDto response = await _userService.CreateUser(createDto);

                if (response.IsSuccess)
                {
                    Success success = new Success(message: SuccessMessages.UserCreated, data: response);
                    return Ok(success);
                }

                Error error = new Error(message: ErrorMessages.UserRegistrationFailed, description: response.Error.Description);
                return BadRequest(error);
            }
            catch (Exception ex)
            {
                return HandleException(ex);
            }
        }

这是我的测试类

    public class MockAccountControllerTests
    {
        readonly UserController _accountController;

        public MockAccountControllerTests()
        {
            Mock<IMapper> _mockMapper = new Mock<IMapper>();
            Mockers.InitializeMappers(_mockMapper);
            UserManager<AppUser> _mockUserManager = Mockers.MockUserManager<AppUser>().Object;
            UserRepository _mockUserRepository = new Mock<UserRepository>(_mockUserManager, _mockMapper.Object).Object;
            UserService _mockUserService = new Mock<UserService>(_mockUserRepository).Object;

            _accountController = new Mock<UserController>(_mockUserService, _mockMapper.Object).Object;
        }

        [Fact]
        public async Task RegisterUser_NullUserNamePassword_ThrowsException()
        {
            CreateUserRequest request = RequestHelpers.CreateUserRequest(null, null);

            IActionResult result = await _accountController.RegisterUser(request);

            ObjectResult badRequest = result as ObjectResult;

            Assert.NotNull(badRequest);
            Assert.True(badRequest is BadRequestObjectResult);
            Assert.Equal(StatusCodes.Status400BadRequest, badRequest.StatusCode);
            Assert.NotNull(badRequest.Value);
            Assert.IsType<Error>(badRequest.Value);
        }
    }

在我的测试方法中的这一行

var result = await _accountController.RegisterUser(request);

resultnull

我还尝试将 BadRequest 的值分配给这样的变量

var a = BadRequest("Test Message"); 在这种情况下,a 也是 null

这将如何纠正? 我在 ActionMethod 或 TestMethod 中做错了吗? 请查看。

【问题讨论】:

  • 阅读How to Ask 并提供minimal reproducible example。你如何初始化你的_accountControllerHandleException() 返回什么?您是否尝试过调试您的测试并单步执行您的代码?
  • result.GetType 的值是多少(查看Immediate Window)?
  • 听着,如果await _accountController.RegisterUser(request) 返回null,那么问题出在你的代码中。在单元测试中,很多 ASP.NET 管道根本没有运行,因此它无法与使用 PostMan 向正在运行的 API 发出请求相提并论。再说一遍:展示你如何初始化_accountController,并单步执行其代码以查看null 的返回位置。我不是很聪明,我是根据多年在 ASP.NET(MVC(核心))中构建和测试的经验告诉你问题出在你的代码中。
  • 我不会感到惊讶,例如,如果您的 _accountControllernew Mock&lt;AccountController&gt;().Object 初始化,因为 BadRequest() 永远不会返回 null。测试模拟是错误的方法,你模拟依赖,而不是被测系统。所以别再在 cmets 和我吵架了,edit 你的问题会展示你的整个测试课。
  • @ArslanMunir 这样做的寓意是,如果你没有在minimal reproducible example 中向我们展示全貌,那么你最终会浪费那些自愿帮助你解决问题的人的时间你的 问题,不必要的来回。

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


【解决方案1】:

唯一可能的解释是,无论result 是什么类型,它都不是从ObjectResult 派生的,因此通过as 将其转换为ObjectResult 会导致返回一个空值。

问题是,我看不到任何输出返回不是从ObjectResult 派生的东西,除了在你返回HandleException(ex) 的catch 块中。目前还不清楚 what 返回的类型在这里,所以我只能假设这就是你的问题所在。简而言之,这需要返回一个ObjectResult 类型。名称中没有 ObjectBadRequestResult 之类的名称源自 StatusCodeResult,它与 ObjectResult 没有血缘关系。

还值得一提的是,一旦你通过了这个断言,你的下一个断言就会失败。由于您将任何结果投射到 ObjectResult 并将其保存到 badRequest,因此断言 Assert.True(badRequest is BadRequestObjectResult) 将始终失败,因为它将始终是 ObjectResult,而不是 BadRequestObjectResult

【讨论】:

    【解决方案2】:

    这行是罪魁祸首:

     _accountController = new Mock<UserController>(_mockUserService, _mockMapper.Object).Object;
    

    不要模拟您的被测系统,因为这样您就不是在测试您的代码,而只是在测试 Moq 是否做了它应该做的事情。确实如此:它为不是 SetUp() 的方法调用返回默认值(null 用于引用类型)。

    因此,请将其初始化为控制器的实际实例:

     _accountController = new UserController(_mockUserService, _mockMapper.Object);
    

    另请参阅:docs.microsoft.com 上的Test controller logic in ASP.NET Core

    【讨论】:

      猜你喜欢
      • 2011-09-23
      • 1970-01-01
      • 1970-01-01
      • 2016-05-20
      • 1970-01-01
      • 2013-06-13
      • 2015-06-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多