测试控制器使用User.Identity.Name的Action

Car*_*any 34 asp.net-mvc nunit unit-testing moq

我有一个依赖于User.Identity.Name的动作来获取当前用户的用户名以获取他的订单列表:

public ActionResult XLineas()
    {
        ViewData["Filtre"] = _options.Filtre;
        ViewData["NomesPendents"] = _options.NomesPendents;
        return View(_repository.ObteLiniesPedido(User.Identity.Name,_options.Filtre,_options.NomesPendents));
    }
Run Code Online (Sandbox Code Playgroud)

现在我正在尝试为此编写单元测试,但我不知道如何为User.Identity.Name提供模拟.如果我按照我的方式运行我的测试(没有模拟用户...),我得到一个Null ..异常.

这是正确的方法吗?我认为我的Action代码不适合单元测试.

Sly*_*Sly 66

您可以使用此代码

public SomeController CreateControllerForUser(string userName) 
{
    var mock = new Mock<ControllerContext>();
    mock.SetupGet(p => p.HttpContext.User.Identity.Name).Returns(userName);
    mock.SetupGet(p => p.HttpContext.Request.IsAuthenticated).Returns(true);

    var controller = new SomeController();
    controller.ControllerContext = mock.Object;

    return controller;
}
Run Code Online (Sandbox Code Playgroud)

它使用Moq模拟框架,但你肯定可以使用任何你喜欢的东西.

  • 在WebAPI中,我确实喜欢这个``MyController controller = new MyController(); controller.User = new GenericPrincipal(new GenericIdentity(username,"Passport"),new [] {"tester"});`` (2认同)

Tom*_*han 21

更好的方法是将一个string参数userName(或一个IPrincipal参数user,如果您需要更多信息而不仅仅是名称)传递给ActionMethod,您可以使用ActionFilterAttribute在正常请求中"注入".当你测试它时,你只需提供你自己的模拟对象,因为动作过滤器的代码将不会运行(在大多数情况下 - 如果你特别想要的话,还有办法)

Kazi Manzur Ra​​shid在一篇优秀的博客文章的第 7点详细描述了这一点.