如何对使用简单成员资格提供程序的控制器进行单元测试?
Controller将MyViewModel对象作为输入&将其插入DB。操作成功完成后,用户将被重定向到仪表板。
Controller将WebSecurity作为依赖项。因此,在单元测试时,我得到HttpContext的参数null异常,在下面的行
中userLakshya.UserId = WebSecurity.HasUserId? WebSecurity.CurrentUserId :-1;
如何将HttpContext参数传递给控制器?
代码列表:
[HttpPost]
public ActionResult Create(MyViewModel myVM)
{
MyModel myModel = myVM.Model;
if (ModelState.IsValid)
{
userLakshya.UserId = WebSecurity.HasUserId ? WebSecurity.CurrentUserId : -1;
db.MyModels.Add(myModel);
db.SaveChanges();
return RedirectToAction("Dashboard");
}
return View(myVM);
}
[TestMethod]
public void TestLoginAndRedirectionToDashboard()
{
MyController cntlr = new MyController();
var ret = ulCntlr.Create(new MyViewModel(){
//Initialize few properties to test
});
/*
* Controller throws parameter null exception for HttpContext
* => Issue: Should I pass this? since the controller uses WebSecurity inside
* */
ViewResult vResult = ret as ViewResult;
if (vResult != null)
{
Assert.IsInstanceOfType(vResult.Model, typeof(UserLakshya));
UserLakshya model = vResult.Model as UserLakshya;
if (model != null)
{
//Assert few properties from the return type.
}
}
}
答案 0 :(得分:1)
您遇到的问题是您的Create方法违反了Dependency Inversion Principle,即您的方法应该“依赖于抽象。不要依赖于具体结果”。
您应该重构代码,以便不使用WebSecurity类,而是使用抽象,例如你可以创建一个ISecurity接口。然后,您的具体版本的ISecurity(例如安全性)可以包含对WebSecurity的引用,从而消除直接依赖关系。
(您已经为数据库依赖关系(即您的数据库成员)执行了此操作,您只需要为代码的安全方面执行此操作。)
e.g。
public Interface ISecurity
{
int GetUserId();
}
然后代替:
userLakshya.UserId = WebSecurity.HasUserId ? WebSecurity.CurrentUserId : -1;
你可以使用:
userLakshya.UserId = security.GetUserId();
然后,为了测试“创建”控制器,您可以使用模拟框架(例如Moq)模拟ISecurity的行为(实际上我还建议模拟“db”对象的行为)。使用Moq代码进行模拟的一个示例是:
var mock = new Mock<ISecurity>();
mock.Setup(security=> security.GetUserId()).Returns("ATestUser");