asp.netフォームの承認をテストするためのモッキングを正常にセットアップしましたが、RoleメンバーシップとAuthorize属性で予期しない動作が見られます。具体的には、以下に示すようにChangePasswordメソッドが呼び出されると、ログオン画面への不正アクセスリダイレクトが発生することが予想されますが、ChangePasswordメソッドを最後まで実行して、パスワードの変更に成功することができます。誰かが私が間違っていることを私に指示するのを手伝ってもらえますか?
ChangePasswordメソッドでIsUserInRoleメソッドを呼び出すと期待どおりに機能し、その状態でログオン画面にリダイレクトできることをテストしましたが、すべてのメソッドでその状態をテストするのは面倒なようです。前もって感謝します。また、(モックでfalseを返す代わりに)ユーザーをロールに割り当てないようにしましたが、結果は同じで、パスワードの変更は成功します。
[TestMethod]
public void TestProfile()
{
string testUserName = "userName", password = "password1", newPassword = "newPassword1";
var prov = new Mock<IMembershipProvider>();
prov.Setup(v => v.ValidateUser(testUserName, password)).Returns(true);
var user = new Mock<MembershipUser>();
var frmAuth = new Mock<IFormsAuthentication>();
user.Setup(v => v.ChangePassword(password, newPassword)).Returns(true);
prov.Setup(v => v.GetUser(testUserName, true)).Returns(user.Object);
AccountController ctrl = new AccountController(prov.Object, frmAuth.Object);
var ctrlCtx = new Mock<ControllerContext>();
ctrlCtx.SetupGet(x => x.HttpContext.User.Identity.Name).Returns(testUserName);
ctrlCtx.SetupGet(x => x.HttpContext.User.Identity.IsAuthenticated).Returns(true);
//with this line I would expect to see a redirect to unauhorized
ctrlCtx.Setup(x => x.HttpContext.User.IsInRole("RoleToTest")).Returns(false);
ctrl.ControllerContext = ctrlCtx.Object;
ctrl.Url = Moq.Mock.Of<IUrlHelper>(x => x.IsLocalUrl(It.IsAny<string>()) == true);
ChangePasswordModel changePass = new ChangePasswordModel() { NewPassword = newPassword, OldPassword = password, ConfirmPassword = password };
var result = ctrl.ChangePassword(changePass) as ViewResult;
string expectedViewName = "Logon";
Assert.AreEqual(result.ViewName, expectedViewName, true /* ignoreCase */,
string.Format("The expected view '{0}' was not returned. Did change password succeed?", expectedViewName));
}
[Authorize(Roles="RoleToTest")]
[HttpPost]
public ActionResult ChangePassword(ChangePasswordModel model)
{
if (ModelState.IsValid)
{
// ChangePassword will throw an exception rather
// than return false in certain failure scenarios.
bool changePasswordSucceeded;
try
{
MembershipUser currentUser = membershipProvider.GetUser(User.Identity.Name, true /* userIsOnline */);
changePasswordSucceeded = currentUser.ChangePassword(model.OldPassword, model.NewPassword);
}
catch (Exception e)
{
Elmah.ErrorSignal.FromCurrentContext().Raise(e);
changePasswordSucceeded = false;
}
if (changePasswordSucceeded)
{
return View("ChangePasswordSuccess");
}
else
{
ModelState.AddModelError("", "The current password is incorrect or the new password is invalid.");
}
}
// If we got this far, something failed, redisplay form
return View("ChangePassword", model);
}