如何为 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>
我有一个 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>