在ASP.NET Core MVC API控制器上单元测试AuthorizeAttribute

Iva*_*van 11 c# unit-testing xunit asp.net-core-mvc .net-core

我有一个ASP.NET核心MVC API与控制器需要进行单元测试.

控制器:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;

namespace TransitApi.Api.Controllers
{
    [Route("api/foo")]
    public class FooController : Controller
    {
        private IFooRepository FooRepository { get; }

        public FooController(IFooRepository fooRepository)
        {
            FooRepository = fooRepository;
        }

        [HttpGet]
        [Authorize("scopes:getfoos")]
        public async Task<IActionResult> GetAsync()
        {
            var foos = await FooRepository.GetAsync();
            return Json(foos);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

至关重要的是,我能够对其有效性进行单元测试AuthorizeAttribute.我们的代码库中存在缺少属性和不正确范围的问题.这个答案正是我正在寻找的,但没有ActionInvoker方法,Microsoft.AspNetCore.Mvc.Controller我不能这样做.

单元测试:

[Fact]
public void GetAsync_InvalidScope_ReturnsUnauthorizedResult()
{
    // Arrange
    var fooRepository = new StubFooRepository();
    var controller = new FooController(fooRepository)
    {
        ControllerContext = new ControllerContext
        {
            HttpContext = new FakeHttpContext()
            // User unfortunately not available in HttpContext
            //,User = new User() { Scopes = "none" }
        }
    };

    // Act
    var result = controller.GetAsync().Result;

    // Assert
    Assert.IsType<UnauthorizedResult>(result);
}
Run Code Online (Sandbox Code Playgroud)

如何对没有正确范围的用户进行单元测试,拒绝访问我的控制器方法?

目前我已经决定只测试AuthorizeAttribute如下的存在,但这实际上不够好:

    [Fact]
    public void GetAsync_Analysis_HasAuthorizeAttribute()
    {
        // Arrange
        var fooRepository = new StubFooRepository();
        var controller = new FooController(fooRepository)
        {
            ControllerContext = new ControllerContext
            {
                HttpContext = new FakeHttpContext()
            }
        };

        // Act
        var type = controller.GetType();
        var methodInfo = type.GetMethod("GetAsync", new Type[] { });
        var attributes = methodInfo.GetCustomAttributes(typeof(AuthorizeAttribute), true);

        // Assert
        Assert.True(attributes.Any());
    }
Run Code Online (Sandbox Code Playgroud)

Nko*_*osi 7

这将需要与内存中测试服务器进行集成测试,因为该属性在框架处理请求管道时由框架进行评估.

ASP.NET Core中的集成测试

集成测试可确保应用程序组件在组装在一起时正常运行.ASP.NET Core支持使用单元测试框架和内置测试Web主机进行集成测试,该主机可用于处理请求而无需网络开销.

[Fact]
public async Task GetAsync_InvalidScope_ReturnsUnauthorizedResult() {
    // Arrange
    var server = new TestServer(new WebHostBuilder().UseStartup<Startup>());
    var client = server.CreateClient();
    var url = "api/foo";
    var expected = HttpStatusCode.Unauthorized;

    // Act
    var response = await client.GetAsync(url);

    // Assert
    Assert.AreEqual(expected, response.StatusCode);
}
Run Code Online (Sandbox Code Playgroud)

如果您不希望测试达到实际的生产实现,您还可以专门为测试创建一个启动,以替换存根/模拟的DI的任何依赖项.

  • 谢谢 - 我们已经将集成测试设置为 Postman 集合。我们将使用它们来测试范围。 (2认同)

小智 6

您可以做的是配置您的测试服务器以添加匿名过滤器中间件:

private HttpClient CreatControllerClient()
{
        return _factory.WithWebHostBuilder(builder
            => builder.ConfigureTestServices(services =>
            {
                // allow anonymous access to bypass authorization
                services.AddMvc(opt => opt.Filters.Add(new AllowAnonymousFilter()));
            })).CreateClient();
}
Run Code Online (Sandbox Code Playgroud)