Unit testing 单元测试Web Api 2模拟用户

Unit testing 单元测试Web Api 2模拟用户,unit-testing,asp.net-web-api,mocking,asp.net-web-api2,Unit Testing,Asp.net Web Api,Mocking,Asp.net Web Api2,我试图在Api控制器测试中模拟User.Identity 这是我的api方法: [Route(Urls.CustInfo.GetCustomerManagers)] public HttpResponseMessage GetCustomerManagers([FromUri]int groupId = -1) { var user = User.Identity.Name; if (IsStaff(user) && gro

我试图在Api控制器测试中模拟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;
        }
        ...
    }
我遵循了这篇文章中的建议:设置用户属性

这是我的测试:

    [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.Identity之前,我甚至尝试将用于设置CurrentPrincipal的行移到api方法中,但它仍然为null

我做错了什么?如果这种方法不适用于WebAPI2,那么模拟/模拟用户属性的最佳方法是什么


谢谢

您可以在
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"});

我确实解决了这个问题,为GetUserId()设置了返回值,而不是答案中投票最多的用户名。很抱歉,oyu将不得不将我使用的假货翻译成你选择的嘲弄工具

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
};
Claim=newclaim(“,userId);
ClaimsIdentity fakeClaimsIdentity=A.Fake();
A.CallTo(()=>fakeClaimsIdentity.FindFirst(A.Ignored)).Returns(claim);
IPrincipal fakeIPrincipal=A.Fake();
A.CallTo(()=>fakeprincipal.Identity).Returns(fakeClaimsIdentity);
var控制器=新授权服务控制器()
{
用户=伪造主体
};

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

虽然这是一篇老文章,但我想补充一下我的想法

如果您只想模拟用户身份,则无需使用任何模拟框架,因为您无法使用模拟框架(至少不能使用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将在WebAPI的控制器中可用


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

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