使用 HttpContext.Current.User.Identity.GetUserId() 对 mvc 模型进行单元测试

Unit testing mvc model with HttpContext.Current.User.Identity.GetUserId()

在我的 MVC5 应用程序中,我有一个日志实体,用于记录对任何控制器的任何调用。此日志使用:HttpContext.Current.User.Identity.GetUserId() 确定访问控制器的用户身份。

public class Log
{
    public Log()
    {
        TS = DateTime.Now;
        UserId = HttpContext.Current.User.Identity.GetUserId();
    }

    [Required]
    public Int32 Id  { get; set; }
    public string UserId { get; set; }

    [Display(Name = "TS", ResourceType = typeof(Resources.Models.Log.Log))]
    [Required(ErrorMessageResourceType = typeof(Resources.Models.Log.Log), ErrorMessageResourceName = "RequiredTS")]
    public DateTime TS { get; set; }

    [Required]
    public short LogTypeId { get; set; }

    [Display(Name = "LogText", ResourceType = typeof(Resources.Models.Log.Log))]
    public string LogText { get; set; }

    public ApplicationUser User { get; set; }
}

当我尝试对控制器进行单元测试并创建日志实例时 class 我收到此错误:

threw exception: System.NullReferenceException: Object reference not set to an instance of an object. at DASU.Core.Models.Log..ctor()

我知道这是因为没有设置上下文。

所以我的问题是如何设置上下文,或者如何模拟上下文,以便为我的测试创建日志?

您应该避免耦合到 HttpContext。就像评论中建议的那样,您可以简化日志,我将 UserId 注入依赖日志 class

public class Log
{
    public Log(string userId)
    {
        TS = DateTime.Now;
        UserId = userId;
    }

    //...other code removed for brevity
}

或者抽象掉对 HttpContext 的调用,这样你就可以模拟你的抽象并注入它,而不是尝试模拟 HttpContext

public interface IUserProvider {
    string GetUserId();
}

您的生产实现可以包装对 HttpContext 的调用,并且您可以轻松地为您的单元测试创​​建模拟实现。

public class Log
{
    public Log(IUserProvider userProvider)
    {
        TS = DateTime.Now;
        UserId = userProvider.GetUserId();
    }

    //...other code removed for brevity
}