在我的MVC项目中,我正在为控制器创建单元测试以返回视图。
此控制器的操作结果将构建一个视图模型,并且该视图模型的构造函数将调用
HttpContext.Current.User.Identity.NameWithoutDomain().ToUpper();
NameWithoutDomain
是IIdentity
的扩展方法。
每当我运行它时,都会不断显示“找不到对象”,我很好奇如何为单元测试适当地模拟它?
扩展方法:
public static class SystemWebExtension
{
public static string NameWithoutDomain(this IIdentity identity)
{
return identity.Name.Split('\\').Last();
}
}
模型构造函数:
public Model()
{
this.PreparedByUser = HttpContext.Current.User.Identity.NameWithoutDomain().ToUpper();
this.AuthorizedBy = true;
this.AuthorizedByUser = HttpContext.Current.User.Identity.NameWithoutDomain().ToUpper();
this.IssueCredit = true;
this.CreateUser = string.IsNullOrEmpty(this.CreateUser) ? Environment.UserName.ToLower() : this.CreateUser;
this.CreateDate = this.CreateDate.HasValue ? this.CreateDate : DateTime.Now;
this.UpdateUser = string.IsNullOrEmpty(this.CreateUser) ? null : Environment.UserName.ToLower();
this.UpdateDate = this.CreateDate.HasValue ? DateTime.Now : (DateTime?) null;
}
答案 0 :(得分:0)
避免耦合到HttpContext
,因为在单元测试时不可用。
您应该将必要的值明确注入模型中
public Model(IIdentity identity) {
this.PreparedByUser = identity.NameWithoutDomain().ToUpper();
this.AuthorizedBy = true;
this.AuthorizedByUser = identity.NameWithoutDomain().ToUpper();
this.IssueCredit = true;
this.CreateUser = string.IsNullOrEmpty(this.CreateUser) ? Environment.UserName.ToLower() : this.CreateUser;
this.CreateDate = this.CreateDate.HasValue ? this.CreateDate : DateTime.Now;
this.UpdateUser = string.IsNullOrEmpty(this.CreateUser) ? null : Environment.UserName.ToLower();
this.UpdateDate = this.CreateDate.HasValue ? DateTime.Now : (DateTime?) null;
}
使用控制器后,您将可以在其属性中访问所需的信息
//...
var model = new Model(this.User.Identity);
return View(model);
在测试时,您可以通过其控制器上下文配置控制器
//...
var username = "some username here"
var identity = new GenericIdentity(username, "");
identity.AddClaim(new Claim(ClaimTypes.Name, username));
var principal = new GenericPrincipal(identity, roles: new string[] { });
var user = new ClaimsPrincipal(principal);
var context = new Mock<HttpContextBase>();
context.Setup(_ => _.User).Returns(user);
//...
controller.ControllerContext = new ControllerContext(context.Object, new RouteData(), controller );
答案 1 :(得分:0)
您不能模拟扩展方法,您必须模拟扩展方法内部发生的事情,以便它返回您想要的值。
要确保NameWithoutDomain
返回您想要的内容,可以模拟IIdentity
并使其返回所需的用户名,如下所示:
var identityMock = new Mock<IIdentity>();
identityMock.SetupGet(x => x.Name).Returns("UsernameWithoutDomain");
如果您要测试NameWithoutDomain
是否完成了预期的工作(即拆分字符串),则可以编写一个单独的测试来调用此扩展方法。
对于HttpContext
,您可以在创建控制器之前实例化它,然后将经过模拟的IIdentity
传递给它,例如(通过WebAPI2测试的 ):< / p>
var identityMock = new Mock<IIdentity>();
identityMock.SetupGet(x => x.Name).Returns("UsernameWithoutDomain");
HttpContext.Current =
new HttpContext(new HttpRequest(null, "http://test.com", null), new HttpResponse(null))
{
User = new GenericPrincipal(identityMock.Object, new[] {"Role1"})
};
var myController = new AccountController();
然后,当您创建控制器实例进行测试时,HttpContext.Current.User.Identity.Name
将返回UsernameWithoutDomain
。测试愉快! :-)