【问题标题】:NullReferenceException in unit test result单元测试结果中的 NullReferenceException
【发布时间】:2015-11-18 11:24:35
【问题描述】:

我刚刚开始使用 C# Webforms 进行编程(之前有 VB Webforms 的经验),我正在制作一个 Web 应用程序,它将成为一个更大项目的一小部分。

我创建了 3 个独立的项目,一个用于 webforms,一个用于类库,一个用于测试。

我已将所有项目添加到一个解决方案中并添加了适当的引用,Webforms 和 Tests 项目都引用了类库。

我在类库中有一个类可以找到登录用户的用户名:

public class LoggedInUser
{
    public string UserName 
    {
        get { return HttpContext.Current.User.Identity.Name; } 
    }

}

在我的一个页面的页面加载事件中,我使用这个类来设置文字的 text 属性以在屏幕上显示名称。

    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; }

任何想法都将一如既往地不胜感激。

【问题讨论】:

  • 单元测试不能依赖任何依赖。您无法在单元测试中获取当前 http 上下文。单元测试没有启动您的网站,因此没有 httpcontext

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


【解决方案1】:

您需要为 HttpContext 创建一个包装类,以抽象出您需要的功能。这样做的原因是 HttpContext 仅存在于 Web 请求中,并且当您从应用程序运行单元测试时,HttpContext 将不存在。

此外,任何第 3 方依赖项都应为其创建一个包装器以帮助进行测试。

值得注意的是,您也根本不需要这个测试。在这种情况下,您正在测试 3rd 方代码,这是您所依赖的准确信息。单元测试的目的是测试您自己的代码/逻辑,如果您为每个 3rd 方方法编写测试,您将永远不会发布产品:)。

至于创建包装类,它们与普通类没有什么不同。您需要为 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;
    }
}

然后您可以注入 HttpContext 的 fake 实现来获得您想要的结果。

【讨论】:

  • 谢谢你,正如我在我是初学者之前所说的那样......我该怎么做你所说的?
【解决方案2】:

实际上,您不一定需要包装和模拟 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 或假实现(或模拟)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多