Test a controller in .Net Core always returns false?

Mohammad Dayyan

I write the following XUnit test to test a .Net Core WebApi controller's action:

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

AccountController:

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

As you see I said usersBusinessObjectMock must return true:

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

But var result = okObjectResult.Value as bool?; is always false

What's wrong?

Test Error Screen Shot

Nkosi

After rechecking how the controller calls the validation method I realized that the problem is that you are not configuring the mock correctly.

The controller is calling

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

Note the ToMd5Hash() being called on the password.

You however setup the mock like...

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

See the problem?

The mock is expecting the raw password and not its hash, thus wont return true when passed the hashed password. This results in the action's object result always returning false because the mock always returns false. That method was hidden off screen so I did not notice it earlier.

So assuming ToMd5Hash() is some custom extension method,

you either setup the mock to expect the hashed password to match the method under test...

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

or use the It.IsAny<>() methods to loosen the expectations of the mock...

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

so that is does not matter what values you pass to the mock, it will always return true

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related