我正在使用Visual Studio 2010的内置测试工具和本文中的类库测试Account/Loggon操作,以创建一个伪控制器上下文。当我运行测试方法时,这个代码行:
FormsAuthentication.SetAuthCookie(username, false);
抛出异常:对象引用未设置为对象的实例
为了测试loggon操作,我认为我应该创建一个带有cookie集合的伪控制器上下文的控制器。这是我的测试代码块:
AccountController controller = new AccountController();
var cookies = new HttpCookieCollection();
controller.ControllerContext = new FakeControllerContext(controller, cookies);
ActionResult result = controller.RemoteLogOn(username, password);
我不确定这是否是正确的方式,但这就是我们所做的,而且有效。
与其直接使用FormsAuthentication.SetAuthCookie
,不如将其抽象为一个接口,例如IFormsAuthenticationService
,并按照正则表达式实现。
在需要的地方,在MVC控制器中接受这一点,例如:
public AccountController(IFormsAuthenticationService formsAuthenticationService)
{
_formsAuthenticationService = formsAuthenticationService; // should use DI here
}
public ActionResult LogOn(string username, string pw)
{
if (yourLogicWhichChecksPw)
_formsAuthenticationService.SetAuthCookie(username, false);
return RedirectToAction("Index");
}
然后在单元测试中,使用类似Moq的东西来伪造接口。
var username = "blah";
var pw = "blah";
var fakesFormsAuth = new Mock<IFormsAuthenticationService>();
fakeFormsAuth.Verify(x => x.SetAuthCookie(username, false), Times.AtLeastOnce());
var controller = new AccountController(fakedFormsAuth.Object);
controller.LogOn(username, pw);
嘲笑这一点的原因是因为绝对不需要对Forms Authentication进行单元测试。它是ASP.NET框架中内置的、经过良好测试且稳定的部分。这就是为什么我们嘲笑那些我们不关心底层实现的事情,相反,我们只测试是否满足某些条件(调用了它,抛出了异常,设置了一些变量,等等)。
测试你自己的代码,而不是.NET.的机制
至于Stephen Walther的文章,当测试中的某些代码需要请求中的数据时,更多的是伪造RequestContext。例如User.Identity、Request.IsAuthenticated、Form变量等。这就是您需要伪造上下文的地方,例如以下代码:
public ActionResult Save(SomeModel)
{
var user = Request.User.Identity; // this will be null, unless you fake the context.
}