代码之家  ›  专栏  ›  技术社区  ›  Mohammad Dayyan

在中测试控制器。Net Core总是返回false?

  •  2
  • Mohammad Dayyan  · 技术社区  · 8 年前

    我编写以下XUnit测试来测试a。Net Core WebApi控制器的操作:

    namespace VistaBest.XUnitTest.Api.Test
    {
        public class Account_UnitTest
        {
            [Fact]
            public void ValidateUserTest()
            {
                const string username = "admin";
                const string password = "admin";
                var usersBusinessObjectMock = new Mock<IUsersBusinessObject>();
                usersBusinessObjectMock.Setup(service => service.ValidateUser(username, password)).Returns(() => true);
                var controller = new AccountController(usersBusinessObjectMock.Object);
                var actionResult = controller.ValidateUser(new LoginModel
                {
                    Username = username,
                    Password = password
                });
                var okObjectResult = Assert.IsType<OkObjectResult>(actionResult);
                var result = okObjectResult.Value as bool?;
                Assert.True(result);
            }
        }
    }
    

    会计控制器 :

    namespace VistaBest.Api.Controllers
    {
        public class AccountController : BaseController
        {
            private readonly IUsersBusinessObject _usersBusinessObject;
            public AccountController(IUsersBusinessObject usersBusinessObject)
            {
                _usersBusinessObject = usersBusinessObject;
            }
    
            [HttpPost]
            public IActionResult ValidateUser(LoginModel model)
            {
                if(!ModelState.IsValid) return BadRequest(ModelState);
                return Ok(_usersBusinessObject.ValidateUser(model.Username, model.Password.ToMd5Hash()));
            }
        }
    }
    

    IUsersBusinessObject :

    namespace VistaBest.Data.BusinessObjects
    {
        public interface IUsersBusinessObject
        {
            bool ValidateUser(string username, string password);
            UserModel SelectByUsername(string username);
        }
    
        public class UsersBusinessObject : BaseBusinessObject, IUsersBusinessObject
        {
            public UsersBusinessObject(IDbConnection connection) : base(connection)
            {
    
            }
    
            private const string TableName = "Users";
    
            public bool ValidateUser(string username, string password)
            {
                var query = $"SELECT COUNT(*) FROM [{TableName}] WHERE UserName = @username and Password = @password";
                return DbConnection.QueryFirst<int>(query, new { username, password }) == 1;
            }
    }
    

    usersBusinessObjectMock 必须返回 true :

    usersBusinessObjectMock
        .Setup(service => service.ValidateUser(username, password))
        .Returns(() => true);
    

    但是 var result = okObjectResult.Value as bool?; 总是 false

    发生了什么?

    Test Error Screen Shot

    3 回复  |  直到 8 年前
        1
  •  6
  •   Kris    8 年前

            var okObjectResult = Assert.IsType<OkObjectResult>(actionResult);
            var result = okObjectResult.Value as bool?;
            Assert.True(result);
    

    但这里有一个错误。。。

    var很危险。。。 您的变量okObjectResult不是来自类型okObjectResult。。。这就是为什么你的断言永远都不是真的。。。 我肯定你的意思是不要打字

    Assert.IsType<OkObjectResult>(actionResult);
    var okObjectResult = (OkObjectResult) actionResult;
    
        2
  •  3
  •   Nkosi    8 年前

    namespace VistaBest.XUnitTest.Api.Test
    {
      public class Account_UnitTest
      {
        private readonly Mock<IUsersBusinessObject> _usersBusinessObjectMock;
        private readonly AccountController _accountController;
        public Account_UnitTest() 
        {
           _usersBusinessObjectMock = new Mock<IUsersBusinessObject>();
           _accountController = new AccountController(_usersBusinessObjectMock.Object);
        }
    
        [Fact]
        public void ValidateUserTest()
        {
            var model = new LoginModel
            {
                Username = "admin",
                Password = "admin"
            };
    
            _usersBusinessObjectMock.Setup(service => service.ValidateUser(model.Username, model.Password)).Returns(() => true);
    
            var actual = _accountController.ValidateUser(model) as OkObjectResult;
    
            actual.Value.ShouldBeEquivalentTo(true); 
            // or Assert.True(actual.Value);
        }
      }
    }
    
        3
  •  1
  •   Nkosi    8 年前

    在重新检查控制器如何调用验证方法后,我意识到问题是您没有正确配置模拟。

    控制器正在呼叫

    _usersBusinessObject.ValidateUser(model.Username, model.Password.ToMd5Hash())
    

    注意 ToMd5Hash() 使用密码调用。

    usersBusinessObjectMock
        .Setup(service => service.ValidateUser(username, password))
        .Returns(() => true);
    

    看到问题了吗?

    模拟需要的是原始密码,而不是其哈希,因此不会返回 true 当传递哈希密码时。这会导致动作的对象结果始终返回 false 因为模拟总是返回 . 这个方法隐藏在屏幕外,所以我之前没有注意到。

    所以假设 ToMd5Hash()

    您可以设置模拟以期望哈希密码与测试中的方法匹配。。。

    usersBusinessObjectMock
        .Setup(service => service.ValidateUser(username, password.ToMd5Hash()))
        .Returns(() => true);
    

    或者使用 It.IsAny<>() 放松模拟预期的方法。。。

    usersBusinessObjectMock
        .Setup(service => service.ValidateUser(It.IsAny<string>(), It.IsAny<string>()))
        .Returns(() => true);
    

    因此,传递给模拟的值并不重要,它总是会返回 真的