单元测试结果中的NullReferenceException

时间:2015-11-18 11:24:36

标签: c# asp.net unit-testing webforms

我刚刚开始使用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; }

任何想法总会受到高度赞赏。

2 个答案:

答案 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或虚假实现(或模拟)。