【问题标题】:Unit Test Web Api 2 Mock User单元测试 Web Api 2 模拟用户
【发布时间】:2014-06-11 05:54:35
【问题描述】:

我试图在我的 Api Controller 测试中模拟 User.Identity。

这是我的api方法:

    [Route(Urls.CustInfo.GetCustomerManagers)]
    public HttpResponseMessage GetCustomerManagers([FromUri]int groupId = -1)
    {
        var user = User.Identity.Name;
        if (IsStaff(user) && groupId == -1)
        {
            return ErrorMissingQueryStringParameter;
        }
        ...
    }

我按照这篇文章中的建议:Set User property for an ApiController in Unit Test 设置了 User 属性。

这是我的测试:

    [TestMethod]
    public void User_Without_Group_Level_Access_Call_GetCustomerManagers_Should_Fail()
    {
        Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity("Bob", "Passport"), new[] {"managers"}); 
        var response = m_controller.GetCustomerManagers();

        Assert.AreEqual(HttpStatusCode.BadRequest, response.StatusCode);
    }

但在运行测试时,User 属性始终为 null。

我什至尝试在调用 User.Identity 之前将设置 CurrentPrincipal 的行移到 api 方法中,但它仍然为空。

我做错了什么?如果这种方法不适用于 web api 2,模拟/模拟 User 属性的最佳方法是什么?

谢谢!

【问题讨论】:

    标签: unit-testing asp.net-web-api mocking asp.net-web-api2


    【解决方案1】:

    您可以在ControllerContext.RequestContext.Principal中设置用户:

    controller.ControllerContext.RequestContext.Principal = new GenericPrincipal(new GenericIdentity("Bob", "Passport"), new[] {"managers"});
    

    或等效的速记:

    controller.User = new GenericPrincipal(new GenericIdentity("Bob", "Passport"), new[] {"managers"});
    

    【讨论】:

    • 这样设置Principal后,没有设置UserId。我需要设置它,因为我的被测系统中的逻辑基于用户 ID。例如。 User.Identity.Name 已填充(“Bob”),但未填充 User.Identity.GetUserId()
    • @Ben Hall 已经有一段时间了,但我想我没有。我认为我的解决方法只是将逻辑更改为使用UserName 而不是UserId
    • @Bart 我确实想出了一个解决方案。请参阅下面的新答案。可能想将其标记为正确答案?
    【解决方案2】:

    虽然是老帖子,但我也想补充一下。

    如果您只想模拟用户身份,则无需使用任何模拟框架,因为您无法使用模拟框架模拟用户身份(至少不能使用 moq)。

    只需如下分配HttpContext.current 属性

    HttpContext.Current = new HttpContext(
        new HttpRequest("", "http://localhost", ""),
        new HttpResponse(null)
    );
    

    HttpContext.Current.User是这样的

    HttpContext.Current.User = 
               new GenericPrincipal(
                   new GenericIdentity("name"),
                   new []{"manager","Admin"}
               );
    

    现在HttpContext.Current.User.Identity.Name 将在 web api 的控制器中可用。

    如果您想模拟其他属性或对象,请使用 moq 或任何其他框架。但是 mocking HttpContext 就跟上面一样简单。

    【讨论】:

      【解决方案3】:

      我确实设法解决了这个问题,实际上为 GetUserId() 设置了一些返回值,而不是在答案中给出的用户名中得票最多。抱歉,oyu 必须将我对 FakeItEasy 的使用转换为您选择的模拟工具。

      Claim claim = new Claim("", userId);
      ClaimsIdentity fakeClaimsIdentity = A.Fake<ClaimsIdentity>();
      A.CallTo(() => fakeClaimsIdentity.FindFirst(A<string>.Ignored)).Returns(claim);
      
      IPrincipal fakeIPrincipal = A.Fake<IPrincipal>();
      A.CallTo(() => fakeIPrincipal.Identity).Returns(fakeClaimsIdentity);
      
      var controller = new AuthorisedServicesController()
      {
            User = fakeIPrincipal
      };
      

      但是更好的解决方案(如果我再次编写代码)是抽象调用 GetUserId 的实际代码,这样我就可以注入一个可以进行该调用的对象,这很容易模拟。有点像工厂。

      【讨论】:

        猜你喜欢
        • 2019-06-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-11-23
        • 2017-09-04
        • 1970-01-01
        相关资源
        最近更新 更多