【发布时间】:2018-02-01 12:07:02
【问题描述】:
我有一个带有需要进行单元测试的控制器的 ASP.NET Core 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);
}
}
}
我必须能够对AuthorizeAttribute 的有效性进行单元测试。我们的代码库中存在属性缺失和范围不正确的问题。 This answer 正是我正在寻找的,但在 Microsoft.AspNetCore.Mvc.Controller 中没有 ActionInvoker 方法意味着我不能这样做。
单元测试:
[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);
}
我如何对没有正确范围的用户进行单元测试,以防止其访问我的控制器方法?
目前我只测试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());
}
【问题讨论】:
-
这需要使用内存测试服务器进行集成测试。
-
为什么测试
AuthorizeAttribute的存在不够好?AuthorizeAttribute既是属性又是IAuthorizationFilter。属性部分不做任何事情,它只是元数据。 MVC 的单元测试保证如果它存在,它将被注册为当前请求和逻辑运行的授权过滤器。如果您使用的是AuthorizeAttribute的子类,那么测试它的逻辑是有意义的,但是由于您不是唯一需要测试的是属性的存在及其属性的配置(Users和@ 987654334@). -
对于第二个 NightOwl888 的评论,我已经创建了扫描我所有控制器操作的测试,以确保它们都定义了一些明确的授权,无论是 AllowAnonymous 还是 Authorized。请注意,它是针对 MVC5 的,我仍然必须将其移植到核心。
-
@Ivan - 如果您需要除少数授权之外的所有方法,那么您可以在启动时全局注册
AuthorizeAttribute,然后使用AllowAnonymous覆盖行为。这样,它们默认情况下被锁定,您不必担心以后的更改会丢失。或者,您可以创建自己的自定义IAuthorizationFilter全局注册,以管理整个应用程序的安全性(甚至可能是您自己的属性来执行某些操作),然后可以将其作为一个单独的部分进行测试,而不是您的控制器和操作。 -
用户拥有允许他们单独访问方法的范围。例如,拥有
scope:bar的用户可能会获得bars 但不会获得foos,反之亦然,拥有scope:all的用户可以同时访问两者。这就是为什么测试这些属性如此重要的部分原因。
标签: c# unit-testing .net-core asp.net-core-mvc xunit