7

I have created a simple action filter in my ASP.NET Core application, this action filter is suppose to log user's activity:

public class AuditAttribute : IResultFilter
{
    private readonly IAuditService _audit;
    private readonly IUnitOfWork _uow;
    public AuditAttribute(IAuditService audit, IUnitOfWork uow)
    {
        _audit = audit;
        _uow = uow;
    }
    public void OnResultExecuting(ResultExecutingContext context)
    {
        ar model = new Audit
        {
            UserName = context.HttpContext.User,
            //...
        };
        _audit.Add(model);
        _uow.SaveChanges();
    }
    public void OnResultExecuted(ResultExecutedContext context)
    {
    }
}

Now I just wanted to know how can I write unit tests for it. I'm using xUnit and Mock

2
  • Mock all the necessary dependencies, exercise the method under test and then verify expected behavior against actual behavior Commented Dec 3, 2016 at 18:02
  • 1
    In the same direction that Nkosi said, I would follow the AAA pattern. Arrange Act Assert Take a look here on how to test your controllers learn.microsoft.com/en-us/aspnet/core/mvc/controllers/testing Commented Dec 3, 2016 at 20:19

2 Answers 2

5

The only way I was able to do this was by creating bare-boned concrete classes and testing the HTTPContext result for what I wanted to achieve. Since I was using concrete classes there was no need for Mock

The setup:

[SetUp]
public void SetUp()
{
   _actionContext = new ActionContext()
   {
      HttpContext = new DefaultHttpContext(),
      RouteData = new RouteData(),
      ActionDescriptor = new ActionDescriptor()
   };
}

The test:

[Test]
public void Should_deny_request()
{
    // Given
    var resourceExecutingContext = new ResourceExecutingContext(_actionContext, new List<IFilterMetadata>(), new List<IValueProviderFactory>());
    var attribute = new YourAttribute();

    // When
    attribute.OnResourceExecuting(resourceExecutingContext);
    var result = (ContentResult) resourceExecutingContext.Result;

    // Then
    Assert.IsTrue(Equals("403", result.StatusCode.ToString()));
}

And this worked for me.

Sign up to request clarification or add additional context in comments.

2 Comments

new ActionDescriptor() seems to require parameters, and I can't figure them out no matter what I do.
Thanks, this was helpful for me to test my exception attribute in asp net code!
0

According to your code, to do unit test, you need to mock the HttpContext as well. BTW this bit doesn't seem right: UserName = context.HttpContext.User I suppose you meant UserName = context.HttpContext.User.Identity.Name. Anyway this is how you test method should look like:

 public void OnResultExecuting_Test()
 {
     // Arrange sesction :
     var httpContextWrapper = new Moq<HttpContextBase>();
     var genericIdentity = new GenericIdentity("FakeUser","AuthType");
     var genericPrincipal = new GenericPrincipal(genericIdentity , new string[]{"FakeRole"});
     httpContextWrapper.Setup(o=> o.User).Return(genericPrincipal);
     var controller = new FakeController(); // you can define a fake controller class in your test class (should inherit from MVC Controller class)
     controller.controllerContext = new ControllerContext( httpContextWrapper.Object, new RouteData(), controller );
     var audit = new Moq<IUnitOfWork>();
     var uow = new Moq<IAuditService>();
     // more code here to do assertion on audit
     uow.Setup(o=>o.SaveChanges()).Verifiable();
     var attribute= new AuditAttribute(audit.Object,uow.Object);

     // Act Section:
     attribute.OnActionExecuting( filterContext );

     // Assert Section:
     ... // some assertions
     uow.Verify();

 }

1 Comment

Where did the filterContext come from?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.