Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing an AuthorizeAttribute on an ASP.NET Core MVC API controller

Tags:

I have a ASP.NET Core MVC API with controllers that need to be unit tested.

Controller:

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);         }     } } 

It is essential that I am able to unit test the effectiveness of the AuthorizeAttribute. We have had issues in our code base with missing attributes and incorrect scopes. This answer is exactly what I am looking for, but not having a ActionInvoker method in Microsoft.AspNetCore.Mvc.Controller means I am not able to do it this way.

Unit Test:

[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); } 

How can I unit test that users without the correct scopes are denied access to my controller method?

Currently I have settled for testing merely the presence of an AuthorizeAttribute as follows, but this is really not good enough:

    [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());     } 
like image 360
08Dc91wk Avatar asked Feb 01 '18 12:02

08Dc91wk


People also ask

Should you write unit tests for controllers?

Unit Testing Controllers Using Moq Library And there is no problem with that approach at all, it is even recommended. But when we write tests for our controller or any other class in a project, we should isolate those dependencies.


1 Answers

This would need integration testing with an in-memory test server because the attribute is evaluated by the framework as it processes the request pipeline.

Integration testing in ASP.NET Core

Integration testing ensures that an application's components function correctly when assembled together. ASP.NET Core supports integration testing using unit test frameworks and a built-in test web host that can be used to handle requests without network overhead.

[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); } 

You can also create a start up specifically for the test that will replace any dependencies for DI with stubs/mocks if you do not want the test hitting actual production implementations.

like image 191
Nkosi Avatar answered Sep 19 '22 04:09

Nkosi