ASP.NET Core 7: how to mock up a controller with role based AuthorizeAttribute

19 views Asked by At

I am currently testing a controller using the xUnit framework. Here is the method I am testing:

[Authorize(Roles = nameof(Roles.Administrator))]
[HttpGet]
public async Task<ActionResult<IEnumerable<AddressDTO>>> GetAllAddresses()
{
  IEnumerable<AddressDTO> addresses = await _addressService.GetAllAddressesAsync();
  return Ok(addresses);
}

The goal of the test I want to perform is to verify that an authenticated user indeed holds the "Administrator" role. If not, the test should fail.

I have attempted several methods:

The first one involves mocking the Service as well as the Controller by specifying a context for it:

[Fact]
public async Task GetAllAddresses_NonAdministrator_Returns_Forbidden()
{
    // Arrange
    var addressServiceMock = new Mock<IAddressService>();
    var controller = new AddressController(addressServiceMock.Object);

    var claims = new List<Claim>
        {
            new Claim(ClaimTypes.Name, "userId"),
            new Claim(ClaimTypes.Role, nameof(Roles.User))
        };
    var identity = new ClaimsIdentity(claims, "TestAuthType");
    var user = new ClaimsPrincipal(identity);
    controller.ControllerContext = new ControllerContext
    {
        HttpContext = new DefaultHttpContext { User = user }
    };

    // Act
    var result = await controller.GetAllAddresses();

    // Assert
    Assert.IsType<ForbidResult>(result.Result);
}

The issue here is that the context is not being considered, and the test runs without taking into account the existence of the [Authorize(Roles = nameof(Roles.Administrator))] attribute.

One of the other method I tried is setting up a mock of an HTTP client using WebApplicationFactory to simulate a request and thus trigger the attribute, which works. However, the problem with this solution is that my test becomes dependent on a database, which I do not want.

Is there a solution to my problem? Am I testing in the wrong way, or should I stick to tests that involve a database?

Thanks in advance for your help!

0

There are 0 answers