How-to test action filters in ASP.NET MVC?
Asked Answered
J

3

15

Need some pointers for this. Found this and this, but I'm still kind a confused.

I just want to mock ActionExecutedContext, pass it, let filter to work a bit and check result.

Any help?

Source of filter you can find here
(it's changed a bit, but that's not a point at the moment).

So - i want unit test, that RememberUrl filter is smart enough to save current URL in session.

Jailer answered 29/6, 2009 at 11:14 Comment(3)
ActionExecutedContext is derived from ControllerContext. Haacked's answer is exactly about mocking ControllerContext - #33140. In what exactly are you confused?Zygotene
Just haven't done it yet. I guess i lack knowledge of asp.net mvc innerworkings. :)Jailer
Then post your code. We will try to help :)Zygotene
Z
12

1) Mocking Request.Url in ActionExecutedContext:

var request = new Mock<HttpRequestBase>();
request.SetupGet(r => r.HttpMethod).Returns("GET");
request.SetupGet(r => r.Url).Returns(new Uri("http://somesite/action"));

var httpContext = new Mock<HttpContextBase>();
httpContext.SetupGet(c => c.Request).Returns(request.Object);

var actionExecutedContext = new Mock<ActionExecutedContext>();
actionExecutedContext.SetupGet(c => c.HttpContext).Returns(httpContext.Object);

2) Suppose you are injecting session wrapper in your RememberUrlAttribute's public constructor.

var rememberUrl = new RememberUrlAttribute(yourSessionWrapper);

rememberUrl.OnActionExecuted(actionExecutedContext.Object);

// Then check what is in your SessionWrapper
Zygotene answered 29/6, 2009 at 12:42 Comment(4)
rememberUrl haven't "ActionExecutedCotnext" method.Jailer
It's OnActionExecuted. Anyway - it seems that i finally got it. Just need to properly mock httpContext. Thanks again - I really appreciate Your help. :)Jailer
any ideas how to test something like this: gist.github.com/raw/88936/… ? :)Jailer
I would start from mocking ViewContext classZygotene
J
3

This is the result:

#region usages

using System;
using System.Collections.Specialized;
using System.Web;
using System.Web.Mvc;
using x.TestBase;
using x.UI.y.Infrastructure.Enums;
using x.UI.y.Infrastructure.Filters;
using x.UI.y.Test.Mocks;
using Moq;

//considering switch to NUnit... :D
using Microsoft.VisualStudio.TestTools.UnitTesting;

#endregion

namespace x.UI.y.Test.Unit.Infrastructure.Filters
{
    [TestClass]
    public class RememberUrlTester : TesterBase
    {
        private static HttpContextBaseMock _context = 
            new HttpContextBaseMock();
        private static ActionExecutedContextMock _actionContext = 
            new ActionExecutedContextMock(_context.Object);

        [TestMethod]
        //"Can save url in session" (i prefer test names in my own language :)
        public void SpeejPieglabaatUrlSesijaa()
        {
            //Arrange
            const string _url = "http://www.foo.bar/foo?bar=bar";
            _context.RequestMock.SetUrl(_url);    
            var filter = new RememberUrlAttribute();

            //Act
            filter.OnActionExecuted(_actionContext.Object);

            //Assert
            _context.SessionMock.Verify
                (m => m.Add(SessionKey.PreviousUrl.ToString(), _url));
        }
    }
}

Wrapped Mock<HttpWhatever> to keep tests clean.

I'm sure things can be done better, but I think it's a great start and I'm feeling quite excited.

Finally that HttpContext monster is under control! ^^

Jailer answered 29/6, 2009 at 23:52 Comment(2)
If it's working for you, that's cool, but the xUnit folks wrote about why they built it, which is worth a read: xunit.codeplex.com/…Gwenngwenneth
@richdiet this one was long ago. I would prefer xUnit nowadays.Jailer
F
0

I know it is an old topic but it might be useful.

This works for me in ASP.NET Core 2.1. I only want to test a filter and to pass a fake action context there.

object resultValue = 123;
var actionContext = new ActionContext(new DefaultHttpContext(), 
                                      new RouteData(), 
                                      new ActionDescriptor());

var context = new ActionExecutedContext(actionContext,
                                        new List<IFilterMetadata>(), 
                                        new object())
                                        {
                                            Result = new ObjectResult(resultValue)
                                        };

IActionFilter filter = new MyFilter();
filter.OnActionExecuted(context);
Feingold answered 15/3, 2021 at 12:4 Comment(1)
I could be helpful if you could edit your answer to the form of unit test, see @ArnisLapsa answer.Schizogenesis

© 2022 - 2024 — McMap. All rights reserved.