我刚刚开始使用C#Webforms编程(之前的VB Webforms经验),我正在制作一个Web应用程序,它将成为更大项目的一小部分。
我创建了3个独立的项目,一个用于webforms,一个用于类库,另一个用于测试。
我已将所有项目添加到一个解决方案中并添加了适当的引用,Webforms和Tests项目都引用了类库。
我在类库中有一个类,它找到登录用户的用户名:
public class LoggedInUser
{
public string UserName
{
get { return HttpContext.Current.User.Identity.Name; }
}
}
在我的某个页面的页面加载事件中,我使用此类设置文字的文本属性以在屏幕上显示名称。
protected void Page_Load(object sender, EventArgs e)
{
LoggedInUser CurrentUser = new LoggedInUser();
LitUser.Text = string.Format(" {0}", CurrentUser.UserName);
}
这很好用。
为了完成,我想我会写一个单元测试,以确保登录的用户名是我所期望的。
[TestMethod]
public void Test_Logged_In_User_Name()
{
LoggedInUser actualUser = new LoggedInUser();
string expectedUserName = "myUserName";
string actualUserName = actualUser.UserName;
Assert.AreEqual(expectedUserName, actualUserName);
}
当我运行测试时,会抛出以下异常:
System.NullReferenceException: Object reference not set to an instance of an object
在这一行:
get { return HttpContext.Current.User.Identity.Name; }
任何想法总会受到高度赞赏。
答案 0 :(得分:1)
您需要为HttpContext创建一个包装类,以抽象您需要的功能。原因是HttpContext仅存在于Web请求中,并且当您从应用程序运行单元测试时,HttpContext将不存在。
此外,任何第三方依赖项都应该为其创建一个包装器以帮助进行测试。
值得注意的是,你根本不需要这个测试。在这种情况下,您正在测试第三方代码,您依赖的是准确的。单元测试的目的是测试您自己的代码/逻辑,如果您为每个第三方方法编写测试,您将永远不会发布产品:)。
至于创建包装类,它们与普通类没有什么不同。您需要为HttpContext类创建一个接口,然后创建一个类似下面的包装器:
public class HttpContextWrapper
{
private readonly IHttpContext _httpContext;
public HttpContextWrapper()
{
_httpContext = HttpContext.Current;
}
public HttpContextWrapper(IHttpContext injectedContext)
{
_httpContext = injectedContext;
}
public string GetName()
{
_httpContext.Current.User.Identity.Name;
}
}
然后,您可以注入一个fake HttpContext,以获得所需的结果。
答案 1 :(得分:0)
实际上,你不一定需要包装和模拟HttpContext。在测试设置中,您可以执行类似以下操作:
var sb = new StringBuilder();
TextWriter writer = new StringWriter(sb);
HttpContext.Current = new HttpContext(
new HttpRequest("path", "http://dummy", ""),
new HttpResponse(writer)
)
{
User = new WindowsPrincipal(WindowsIdentity.GetCurrent())
};
在此示例中,我为Windows主体分配了当前用户的标识,但在您的方案中,您可能希望分配一个特制的主体,例如ClaimsPrincipal或虚假实现(或模拟)。