单元测试 - 如何将控制器用户设置为Generic Principal对象

时间:2017-10-10 12:34:43

标签: c# unit-testing asp.net-web-api tdd asp.net-apicontroller

更新了完整解决方案:

我要测试的WebApi控制器方法:

using Microsoft.AspNet.Identity;
using System.Web.Http;


[Authorize]
public class GigsController : ApiController
{
    private readonly IUnitOfWork _unitOfWork;

    public GigsController(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }        

    [HttpDelete]
    public IHttpActionResult Cancel(int id)
    {
        var userId = User.Identity.GetUserId();
        var gig = _unitOfWork.Gigs.GetGigWithAttendees(id);

        if (gig.IsCanceled)
            return NotFound();

        if (gig.ArtistId != userId)
            return Unauthorized();

        gig.Cancel();

        _unitOfWork.Complete();

        return Ok();
    }
}

单元测试类:

[TestClass]
public class GigsControllerTests
{
    private GigsController _controller;
    public GigsControllerTests()
    {
        var identity = new GenericIdentity("user1@domain.com");
        identity.AddClaim(
            new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", "user1@domain.com"));
        identity.AddClaim(
            new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", "1"));

        var principal = new GenericPrincipal(identity, null);

        var mockUoW = new Mock<IUnitOfWork>();
        _controller = new GigsController(mockUoW.Object);
        _controller.User = principal;
    }

我收到了以下错误:

  

错误CS0200属性或索引器&#39; ApiController.User&#39;不可能是   分配给 - 它是只读的

https://i.stack.imgur.com/YDQJS.png

4 个答案:

答案 0 :(得分:2)

我在遵循Moshi的教程时遇到了同样的问题,在我终于能够解决这个问题之前,这让我困扰了好几个小时。

最终,解决这个问题的是改变我的使用陈述:

使用GigHub.Controllers;

使用GigHub.Controllers.Api;

你的GigsController _controller指向Controller本身,而不是ApiController。我有点希望Moshi将“Api”放在他的API类的名称中,这样你就可以知道如果你正在查看纯控制器或控制器的API版本,而无需检查命名空间或转到对象的定义。

你是对的,Controller类的User属性确实只有Get。

public abstract class Controller : ControllerBase, IActionFilter, 
IAuthenticationFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, 
IResultFilter, IAsyncController, IController, IAsyncManagerContainer
{
   public IPrincipal User { get; }
}

然而,ApiController类的User属性同时具有Get和Set。

public abstract class ApiController : IHttpController, IDisposable
{
    public IPrincipal User { get; set; }
}

希望这也是你的问题,并帮助你!

干杯!

答案 1 :(得分:1)

而是设置执行线程的CurrentPrincipal

Thread.CurrentPrincipal = principal;

答案 2 :(得分:1)

您可以通过ControllerContext

分配
var user = new ClaimsPrincipal();
var context = new ControllerContext
{
    HttpContext = new DefaultHttpContext
    {
        User = user
    }
};

controllerUnderTest.ControllerContext = context;

答案 3 :(得分:0)

当我试图在控制器中模拟用户而不是controller.api时,出现在这篇文章中,并感到困惑。 无论如何,方法是通过使用模拟对象覆盖控制器中的ControllerContext,并将模拟对象设置为返回您想要模拟的用户。

var user = CreateLoggedInUser(targetUserID);

mockControllerContext = new Mock<ControllerContext>();

mockControllerContext.Setup(o => o.HttpContext.User).Returns(user);

myCaseController.ControllerContext = mockControllerContext.Object;

private ClaimsPrincipal CreateLoggedInUser(int userID)
    {
        GenericIdentity myIdentity = new GenericIdentity("apiTestUser");
        myIdentity.AddClaims(new List<Claim> {
            new Claim(ClaimTypes.Sid, userID.ToString()),

        });
        return new ClaimsPrincipal(myIdentity);
    }