如何为 MVC 5 控制器模拟 OWINContext

How to mock OWINContext for MVC 5 controller

我有一个 BaseController,我的所有控制器都派生自它,它在 ViewBag 中设置一个值(用户的昵称)。我这样做是为了可以在布局中访问该值,而不必为每个控制器隐式设置它(如果您只是建议更好的方法,请继续!)。

public class BaseController : Controller
{
    public BaseController()
    {
        InitialiseViewBag();
    }

    protected void InitialiseViewBag()
    {
        ApplicationUser user = System.Web.HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>().FindById(System.Web.HttpContext.Current.User.Identity.GetUserId());

        ViewBag.NickName = user?.NickName;
    }
}

然后我得出 class,例如,在 HomeController 中:

public class HomeController : BaseController
{
    private readonly IRoundRepository _repository = null;

    public HomeController(IRoundRepository repository)
    {
        _repository = repository;
    }

    public ActionResult Index()
    {
        return View();
    }
}

我已经设置了我的控制器的其他依赖项(存储库,在此处未显示的另一个视图中使用)进入构造函数,并且正在使用 StructureMap 进行 DI,当我取出BaseController 中用于获取昵称的行。

问题是当我包含该行以使用 OWIN 上下文获取昵称时,我的测试失败了

System.InvalidOperationException: No owin.Environment item was found in the context.

这是我目前的测试:

[TestMethod]
public void HomeControllerSelectedIndexView()
{
    // Arrange
    HttpContext.Current = _context;
    var mockRoundRepo = new Mock<IRoundRepository>();
    HomeController controller = new HomeController(mockRoundRepo.Object);

    // Act
    ViewResult result = controller.Index() as ViewResult;

    // Assert
    Assert.IsNotNull(result);
}

我想我明白为什么它不起作用,但我不知道如何解决它。

我应该如何 mocking/injecting/otherwise 设置这个基本控制器,以便它可以访问用户的身份并且在我的测试期间不会摔倒?

注意:我对使用依赖项注入还很陌生,所以如果这很明显,或者我的做法完全错误,或者遗漏了任何重要信息,我都不会感到惊讶!

我使用声明解决了这个问题,感谢 Nkosi 的建议。

在我的 ApplicationUser.GenerateUserIdentityAsync() 方法中,我将声明添加到他们的身份中:

userIdentity.AddClaim(new Claim("NickName", this.NickName));

我添加了一个辅助扩展方法来访问 Identity 对象的 NickName 声明:

public static class IdentityExtensions
{
    public static string GetNickName(this IIdentity identity)
    {
        var claim = ((ClaimsIdentity)identity).FindFirst("NickName");

        // Test for null to avoid issues during local testing
        return (claim != null) ? claim.Value : string.Empty;
    }
}

现在在我的视图(或控制器)中我可以直接访问声明,例如:

<span class="nickname">@User.Identity.GetNickName()</span>