是否可以使用模拟对象作为另一种模拟方法的输入?
Is it possible to use a mocked object as an input for another method up for mocking?
我创建了一个以前的测试方法,在单个数据访问上设置了两个模拟对象,它运行良好。用同样的场景做了另一个,但结果失败了。
测试方法如下:
[Test]
public void UpdateUserPassword_WhenInputsAreCorrect_ReturnsQuerySuccessMessage()
{
UpdatePasswordModel input = new UpdatePasswordModel()
{
UserName = "john.doe",
NewPassword = "password1", //password1
PreviousPassword = "password" //password
};
Mock<IUserDataAccess> user = new Mock<IUserDataAccess>();
Mock<IDailyTimeInDataAccess> timeIn = new Mock<IDailyTimeInDataAccess>();
Mock<IDailyTimeOutDataAccess> timeOut = new Mock<IDailyTimeOutDataAccess>();
user.Setup(x => x.UpdatePassword(10000, input.NewPassword)).Returns("User record updated.");
user.Setup(x => x.GetUser(input.UserName)).Returns(new User()
{
UserKey = 10000,
UserName = "john.doe",
UserPassword = "LTg9BIob8urwz643K5+pBA=="
});
ILoginBusinessRules app = new LoginBusinessRules(user.Object, timeIn.Object, timeOut.Object);
var output = app.UpdateUserPassword(input);
Assert.AreEqual("User record updated.", output);
}
业务规则如下:
public string UpdateUserPassword(UpdatePasswordModel model)
{
if (model == null)
{
return "No data to process.";
}
if (string.IsNullOrEmpty(model.UserName))
{
return "Username is empty.";
}
if (string.IsNullOrEmpty(model.NewPassword))
{
return "New Password is empty.";
}
if (string.IsNullOrEmpty(model.PreviousPassword))
{
return "Previous Password is empty.";
}
var user = _userDataAccess.GetUser(model.UserName);
if (user == null)
{
return "User not found.";
}
if (user.UserPassword != EncryptPassword(model.PreviousPassword))
{
return "Previous password does not match.";
}
else
{
user.UserPassword = EncryptPassword(model.NewPassword);
user.UpdateDttm = DateTime.Now;
user.UpdateUserId = model.UserName;
var result = _userDataAccess.UpdatePassword(user.UserKey, user.UserPassword);
return result;
}
}
测试返回失败。进一步调试告诉我,这里的这一行返回 null:
var result = _userDataAccess.UpdatePassword(user.UserKey, user.UserPassword);
非常感谢任何帮助!
要回答 post 中的问题,是的,您可以使用与输入类型匹配的任何对象。您的代码并不知道 "mock" 和 "real" 对象之间的区别。
Setup
使用input.NewPassword
,测试结果为
UpdatePasswordModel input = new UpdatePasswordModel() {
//...
NewPassword = "password1",
//...
};
//...
user.Setup(x => x.UpdatePassword(10000, input.NewPassword)).Returns("User record updated.");
//...
但在被测方法中,该方法是用另一个值调用的
//...
user.UserPassword = EncryptPassword(model.NewPassword);
//...
var result = _userDataAccess.UpdatePassword(user.UserKey, user.UserPassword);
这与设置中的预期不符。
当模拟成员未按预期调用时,它将 return 默认 return 类型,在本例中为 null
您需要确保在设置期望中使用了正确的值
例如
user
.Setup(x => x.UpdatePassword(10000, EncryptPassword(input.NewPassword)))
.Returns("User record updated.");
或者使用像 It.IsAny<T>()
这样的参数匹配器放宽对设置的期望
user
.Setup(x => x.UpdatePassword(10000, It.IsAny<string>()))
.Returns("User record updated.");
我创建了一个以前的测试方法,在单个数据访问上设置了两个模拟对象,它运行良好。用同样的场景做了另一个,但结果失败了。
测试方法如下:
[Test]
public void UpdateUserPassword_WhenInputsAreCorrect_ReturnsQuerySuccessMessage()
{
UpdatePasswordModel input = new UpdatePasswordModel()
{
UserName = "john.doe",
NewPassword = "password1", //password1
PreviousPassword = "password" //password
};
Mock<IUserDataAccess> user = new Mock<IUserDataAccess>();
Mock<IDailyTimeInDataAccess> timeIn = new Mock<IDailyTimeInDataAccess>();
Mock<IDailyTimeOutDataAccess> timeOut = new Mock<IDailyTimeOutDataAccess>();
user.Setup(x => x.UpdatePassword(10000, input.NewPassword)).Returns("User record updated.");
user.Setup(x => x.GetUser(input.UserName)).Returns(new User()
{
UserKey = 10000,
UserName = "john.doe",
UserPassword = "LTg9BIob8urwz643K5+pBA=="
});
ILoginBusinessRules app = new LoginBusinessRules(user.Object, timeIn.Object, timeOut.Object);
var output = app.UpdateUserPassword(input);
Assert.AreEqual("User record updated.", output);
}
业务规则如下:
public string UpdateUserPassword(UpdatePasswordModel model)
{
if (model == null)
{
return "No data to process.";
}
if (string.IsNullOrEmpty(model.UserName))
{
return "Username is empty.";
}
if (string.IsNullOrEmpty(model.NewPassword))
{
return "New Password is empty.";
}
if (string.IsNullOrEmpty(model.PreviousPassword))
{
return "Previous Password is empty.";
}
var user = _userDataAccess.GetUser(model.UserName);
if (user == null)
{
return "User not found.";
}
if (user.UserPassword != EncryptPassword(model.PreviousPassword))
{
return "Previous password does not match.";
}
else
{
user.UserPassword = EncryptPassword(model.NewPassword);
user.UpdateDttm = DateTime.Now;
user.UpdateUserId = model.UserName;
var result = _userDataAccess.UpdatePassword(user.UserKey, user.UserPassword);
return result;
}
}
测试返回失败。进一步调试告诉我,这里的这一行返回 null:
var result = _userDataAccess.UpdatePassword(user.UserKey, user.UserPassword);
非常感谢任何帮助!
要回答 post 中的问题,是的,您可以使用与输入类型匹配的任何对象。您的代码并不知道 "mock" 和 "real" 对象之间的区别。
Setup
使用input.NewPassword
,测试结果为
UpdatePasswordModel input = new UpdatePasswordModel() {
//...
NewPassword = "password1",
//...
};
//...
user.Setup(x => x.UpdatePassword(10000, input.NewPassword)).Returns("User record updated.");
//...
但在被测方法中,该方法是用另一个值调用的
//...
user.UserPassword = EncryptPassword(model.NewPassword);
//...
var result = _userDataAccess.UpdatePassword(user.UserKey, user.UserPassword);
这与设置中的预期不符。
当模拟成员未按预期调用时,它将 return 默认 return 类型,在本例中为 null
您需要确保在设置期望中使用了正确的值
例如
user
.Setup(x => x.UpdatePassword(10000, EncryptPassword(input.NewPassword)))
.Returns("User record updated.");
或者使用像 It.IsAny<T>()
user
.Setup(x => x.UpdatePassword(10000, It.IsAny<string>()))
.Returns("User record updated.");