在运行我的单元测试方法时,我收到错误FormsAuthentication.SignOut()。我像这样嘲笑httpcontext
var httpRequest = new HttpRequest("", "http://localhost/", "");
var stringWriter = new StringWriter();
var httpResponse = new HttpResponse(stringWriter);
var httpContext = new HttpContext(httpRequest, httpResponse);
var sessionContainer = new HttpSessionStateContainer(
"id",
new SessionStateItemCollection(),
new HttpStaticObjectsCollection(),
10,
true,
HttpCookieMode.AutoDetect,
SessionStateMode.InProc,
false);
SessionStateUtility.AddHttpSessionStateToContext(httpContext, sessionContainer);
var controller = new AccountController();
var requestContext = new RequestContext(new HttpContextWrapper(httpContext), new RouteData());
controller.ControllerContext = new ControllerContext(requestContext, controller);
var actual = controller.Login(new CutomerModel() { Login = "admin", Password = "Password1" });
return httpContext;
在登录方法
中public ActionResult Login(CutomerModel obj)
{
FormsAuthentication.SignOut();
}
FormsAuthentication.SignOut();
抛出
'对象引用未设置为对象的实例。 “
答案 0 :(得分:3)
静态方法FormsAuthentication.SignOut
依赖于另一个静态成员HttpContext.Current
,它在单元测试期间不可用。将控制器紧密耦合到静态的HttpContext.Current
会导致代码很难测试。尽量避免耦合到静态调用。
附注:难以为代码设置单元测试,这是一个明确的迹象,表明需要对其进行审核并且很可能会重构。
Abstract FormsAuthentication
调用他们自己的关注/接口,以便他们可以被模拟。
public interface IFormsAuthenticationService {
void SignOut();
//...other code removed for brevity
}
生产代码可以包装实际调用,该调用应该可用HttpContext.Current
。确保DI容器知道如何解决依赖关系。
public class FormsAuthenticationService : IFormsAuthenticationService {
public void SignOut() {
FormsAuthentication.SignOut();
}
//...other code removed for brevity
}
重构控制器以依赖抽象而不是实现问题。
public class AccountController : Controller {
//...other code removed for brevity.
private readonly IFormsAuthenticationService formsAuthentication;
public AccountController(IFormsAuthenticationService formsAuthentication) {
//...other arguments removed for brevity
this.formsAuthentication = formsAuthentication;
}
public ActionResult Login(CutomerModel obj) {
formsAuthentication.SignOut();
//...
return View();
}
//...other code removed for brevity.
}
和示例测试
注意:我使用Moq来模拟依赖项,使用FluentAssertions来断言结果。
[TestMethod]
public void LoginTest() {
//Arrange
var model = new CutomerModel() { Login = "admin", Password = "Password1" };
var mockFormsAuthentication = new Mock<IFormsAuthenticationService>();
var controller = new AccountController(mockFormsAuthentication.Object);
//Act
var actual = controller.Login(model) as ViewResult;
//Assert (using FluentAssertions)
actual.Should().NotBeNull(because: "the actual result should have the returned view");
mockFormsAuthentication.Verify(m => m.SignOut(), Times.Once);
}