xUnit ClaimsPrincipal模拟并传递给控制器​​User为null

问题描述

我一直在阅读文章,试图弄清楚这一点。本文How to add claims in a mock ClaimsPrincipal的结构部分。我仍然从控制器中获取用户,并且对控制器内User的空对象的测试失败。

BusinessController

    [Route("api/[controller]")]
    [ApiController]
    public class BusinessController : ControllerBase
    {
        private readonly IGBusinessRepository businessRepository;
        private readonly IPersonRepository personRepository;
        private readonly IUserClaims userClaims;

        public BusinessController(IGBusinessRepository businessRepository,IPersonRepository personRepository,IUserClaims userClaims)
        {
            this.businessRepository = businessRepository;
            this.personRepository = personRepository;
            this.userClaims = userClaims;
        }

        // GET api/<BusinessController>/5
        [HttpGet("{id}")]
        [Authorize]
        public async Task<IActionResult> GetBusiness(Guid businessId)
        {
            var userGuid = userClaims.GetUserGuid(User.Claims);
            var ownerId = await personRepository.GetPersonIdByGUID(userGuid);
            var business = await businessRepository.GetBusinessById(businessId);
            if(business != null && business.OwnerId == businessId)
            {
                return Ok(business);
            }

            return BadRequest("Bad business id or your not the owner");            
        }

UserClaims

    public class UserClaims : IUserClaims
    {
        public string GetUserGuid(IEnumerable<Claim> claims)
        {
            var claimType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier";
            var guidClaim = claims.Where(c => c.Type == claimType).Select(s => s.Value).SingleOrDefault();


            return guidClaim;
        }
    }

TestIdentity

    public class TestIdentity : ClaimsIdentity
    {
        public TestIdentity(params Claim[] claims) : base(claims)
        {

        }
    }

TestPrincipal

    public class TestPrincipal : ClaimsPrincipal
    {
        public TestPrincipal(params Claim[] claims) : base(new TestIdentity(claims))
        {

        }
    }

BusinessControllerTests

    public class BusinessControllerTests
    {
        //Controller 
        private readonly Mock<IGBusinessRepository> mockBusinessRepository;
        private readonly Mock<IPersonRepository> mockPersonRepository;
        private readonly Mock<IUserClaims> mockUserClaims;
        private BusinessController controller;

        //Objects
        private Guid id = Guid.NewGuid(); 

        public BusinessControllerTests()
        {
            mockBusinessRepository = new Mock<IGBusinessRepository>();
            mockPersonRepository = new Mock<IPersonRepository>();
            mockUserClaims = new Mock<IUserClaims>();
            controller = new BusinessController(mockBusinessRepository.Object,mockPersonRepository.Object,mockUserClaims.Object);
        }

        [Fact]
        public async Task GetBussiness_NotBusinessOwner_ReturnsBadRequest()
        {
            //Arrange
            var userGuidString = Guid.NewGuid().ToString();
            var ownerId = Guid.NewGuid();
            var userClaim = new TestPrincipal(new Claim("name","[email protected]"));
            Thread.CurrentPrincipal = userClaim;
            
            //mockUserClaims.Setup(repo => repo.GetUserGuid(userClaim)).Returns(userGuidString);
            mockPersonRepository.Setup(repo => repo.GetPersonIdByGUID(userGuidString));
            mockBusinessRepository.Setup(repo => repo.GetBusinessById(id)).ReturnsAsync(business);

            //Act
            var result = await controller.GetBusiness(id);

            //Assert
            Assert.IsType<BadRequestResult>(result);
        }

        private GobiezBusiness business = new GobiezBusiness()
        {
            Id = new MongoDB.Bson.ObjectId(),BusinessId = Guid.NewGuid(),Name = "Test",Email = "[email protected]",Address = "123 A street",State = "WA",ZipCode = "12345",PhoneNumber = "123-456-7890",OwnerId = Guid.NewGuid()
        };   
    }

解决方法

未正确配置控制器以访问主体

// ... omitted for brevity

var userClaim = new TestPrincipal(new Claim("name","[email protected]"));
var httpContext = new DefaultHttpContext() {
    User = userClaim;
};

//Controller needs a controller context to access HttpContext
var controllerContext = new ControllerContext() {
    HttpContext = httpContext
};

//assign context to controller    
BusinessController controller = new BusinessController(
    mockBusinessRepository.Object,mockPersonRepository.Object,mockUserClaims.Object)
{
    ControllerContext = controllerContext
};

//Act
var result = await controller.GetBusiness(id);

// ... omitted for brevity

还应在正在执行的测试范围内创建控制器。

这行在被测对象中

//...

var userGuid = userClaims.GetUserGuid(User.Claims);

//...

现在应该返回测试中安排的创建的TestPrincipal