C# 测试.Net Core中的控制器是否总是返回false?
我编写以下XUnit测试来测试.Net核心WebApi控制器的操作:C# 测试.Net Core中的控制器是否总是返回false?,c#,unit-testing,asp.net-core,moq,xunit.net,C#,Unit Testing,Asp.net Core,Moq,Xunit.net,我编写以下XUnit测试来测试.Net核心WebApi控制器的操作: namespace VistaBest.XUnitTest.Api.Test { public class Account_UnitTest { [Fact] public void ValidateUserTest() { const string username = "admin"; const string
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);
}
}
}
IUsersBusinessObject:
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()));
}
}
}
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;
}
}
但是var result=okObjectResult.Value为bool代码>总是false
怎么了
在阅读代码10分钟后,因为很难找到这个错误。你做的一切都对
var okObjectResult = Assert.IsType<OkObjectResult>(actionResult);
var result = okObjectResult.Value as bool?;
Assert.True(result);
var-okObjectResult=Assert.IsType(actionResult);
var结果=okObjectResult.值为bool?;
断言.True(结果);
但这里有一个错误
var是危险的。。。
您的变量okObjectResult不是来自okObjectResult类型。。。这就是为什么你的断言永远不正确。。。
我肯定你不想打字
Assert.IsType<OkObjectResult>(actionResult);
var okObjectResult = (OkObjectResult) actionResult;
Assert.IsType(actionResult);
var okObjectResult=(okObjectResult)actionResult;
这将起作用,我将在您的代码中进行一些小的重构
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);
}
}
}
namespace VistaBest.XUnitTest.Api.Test
{
公共类帐户单元测试
{
私有只读Mock_usersBusinessObjectMock;
私有只读AccountController\u AccountController;
公共帐户单元测试()
{
_usersBusinessObjectMock=新建Mock();
_accountController=新的accountController(_usersBusinessObjectMock.Object);
}
[事实]
公共void ValidateUserTest()
{
var模型=新的LoginModel
{
Username=“admin”,
Password=“admin”
};
_usersBusinessObjectMock.Setup(service=>service.ValidateUser(model.Username,model.Password))。返回(()=>true);
var actual=_accountController.ValidateUser(model)作为OkObjectResult;
实际值应等于(真);
//或Assert.True(实际值);
}
}
}
重新检查控制器如何调用验证方法后,我意识到问题在于您没有正确配置模拟
控制器正在呼叫
_usersBusinessObject.ValidateUser(model.Username, model.Password.ToMd5Hash())
请注意,正在对密码调用ToMd5Hash()
但是,您可以像
usersBusinessObjectMock
.Setup(service => service.ValidateUser(username, password))
.Returns(() => true);
看到问题了吗
mock需要的是原始密码而不是散列密码,因此在传递散列密码时不会返回true
。这导致操作的对象结果总是返回false
,因为模拟总是返回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);
usersBusinessObjectMock
.Setup(service=>service.ValidateUser(It.IsAny(),It.IsAny())
.返回(()=>true);
因此,无论您传递给mock的值是什么,它都将始终返回true
请注意,假设将提供的对象强制转换为提供的类型。我像您编写的那样更改代码,没有任何更改,并且okObjectResult值始终为false!如果您只是将值强制转换为布尔值ievar result=(bool)okObjectResult.value代码>@Nkosi:结果总是错误的,请看主要帖子图片中的“手表”部分。我们关注的是错误的事情。模拟未正确配置,因此表现不符合预期。检查我提供的答案。我像你写的那样更改代码,没有任何更改,实际值。值始终为false!太好了,非常感谢
usersBusinessObjectMock
.Setup(service => service.ValidateUser(It.IsAny<string>(), It.IsAny<string>()))
.Returns(() => true);