我正在使用Moq和Microsoft的测试工具为使用ASP.NET身份的ASP.NET MVC 5应用编写单元测试。测试需要在Login
POST操作中模拟登录失败,以便从SignInStatus.Failure
的{{1}}方法生成SignInManager.PasswordSignInAsync
:
AccountController
以下是[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login([Bind(Include = "Email,Password,RememberMe")]
LoginViewModel model, string returnUrl)
{
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password,
model.RememberMe, shouldLockout: true);
switch (result)
{
case SignInStatus.Success:
return Redirect(returnUrl);
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresVerification:
case SignInStatus.Failure:
default:
ModelState.AddModelError("", "Invalid login attempt.");
return View(model);
}
}
上的帮助成员/方法:
[TestClass]
这是我的测试方法:
private Mock<HttpContextBase> _httpContextMock;
private Mock<HttpRequestBase> _httpRequestMock;
private Mock<HttpResponseBase> _httpResponseMock;
private MyApp.Controllers.AccountController _controller;
private Mock<ControllerContext> _controllerContextMock;
[TestInitialize]
public void SetupTests()
{
// Set up Moq
_httpContextMock = new Mock<HttpContextBase>();
_httpRequestMock = new Mock<HttpRequestBase>();
_httpResponseMock = new Mock<HttpResponseBase>();
_controller = new AccountController();
_controllerContextMock = new Mock<ControllerContext>();
}
private void SetContexts(IPrincipal user)
{
_httpContextMock.Setup(x => x.Items).Returns(new Dictionary<string, object>());
var sessionContainer = new HttpSessionStateContainer("id", new SessionStateItemCollection(),
new HttpStaticObjectsCollection(), 10, true,
HttpCookieMode.AutoDetect,
SessionStateMode.InProc, false);
//this adds aspnet session
_httpContextMock.Object.Items["AspSession"] = typeof(HttpSessionState).GetConstructor(
BindingFlags.NonPublic | BindingFlags.Instance,
null, CallingConventions.Standard,
new[] { typeof(HttpSessionStateContainer) },
null)
.Invoke(new object[] { sessionContainer });
_httpContextMock.Setup(x => x.User).Returns(user);
// https://stackoverflow.com/questions/674458/asp-net-mvc-unit-testing-controllers-that-use-urlhelper
_httpRequestMock.SetupGet(x => x.ApplicationPath).Returns("/");
_httpRequestMock.SetupGet(x => x.Url).Returns(new Uri("http://localhost/a", UriKind.Absolute));
_httpRequestMock.SetupGet(x => x.ServerVariables).Returns(new NameValueCollection());
_httpResponseMock.Setup(x => x.ApplyAppPathModifier(It.IsAny<string>())).Returns<string>(x => x);
var routes = new RouteCollection();
RouteConfig.RegisterRoutes(routes);
var helper = new UrlHelper(new RequestContext(_httpContextMock.Object, new RouteData()), routes);
_httpContextMock.SetupGet(x => x.Request).Returns(_httpRequestMock.Object);
_httpContextMock.SetupGet(x => x.Response).Returns(_httpResponseMock.Object);
// https://stackoverflow.com/questions/4066184/httpresponsebase-headers-are-empty-when-running-test
_httpResponseMock.Setup(r => r.OutputStream).Returns(new MemoryStream());
_httpResponseMock.Setup(r => r.Headers).Returns(new NameValueCollection());
var userStore = new Mock<IUserStore<ApplicationUser>>();
var userManager = new Mock<ApplicationUserManager>(userStore.Object);
var authenticationManager = new Mock<IAuthenticationManager>();
var signInManager = new Mock<ApplicationSignInManager>(userManager.Object, authenticationManager.Object);
var data = new Dictionary<string, object>()
{
{"a", "b"} // fake whatever you need here.
};
// https://stackoverflow.com/a/28574389/177416
_controller = new AccountController(
userManager.Object, signInManager.Object)
{
ControllerContext = new ControllerContext()
{
HttpContext = _httpContextMock.Object
}
};
_controller.ControllerContext.HttpContext.Items["owin.Environment"] = data;
_controller.Url = helper;
}
如您所见,我有模拟[TestMethod]
public async Task NoViewReturnedForFailedLogin()
{
// Arrange
var claimsIdentity = new ClaimsIdentity();
claimsIdentity.AddClaim(new Claim(ClaimTypes.Name, "fake@fake.org"));
var claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
SetContexts(claimsPrincipal);
var vm = new LoginViewModel
{
Email = "faker@gmail.com",
Password = "Faker9999!",
RememberMe = false
};
_controllerContextMock.SetupGet(p => p.HttpContext.User.Identity.Name).Returns(vm.Email);
_controllerContextMock.SetupGet(p => p.HttpContext.Request.IsAuthenticated).Returns(false);
// Act
var result = await _controller.Login(vm, "http://www.google.com") as RedirectToRouteResult;
// Assert
// ? What do I assert?
}
,userStore
,userManager
和authenticationManager
。如果我单步执行signInManager
操作,则Login
始终返回result
。
有没有办法让它失败?测试断言应该是什么?