Solved

HttpResponseBase.Cache invocation failed with mock behavior strict error

Posted on 2014-03-28
5
971 Views
Last Modified: 2014-04-30
I am trying to do TDD under ASP.NET C# MVC 4.  I am trying to test a custom attribute and when the test is successful and returns true I get the above error.  I tried changing my MockBehavior to Loose but it still throws an exception.

What is the best way to Mock the HttpResponseBase?  Here is what I have so far:

AuthUser AuthorizeAttribute:
    public class AuthUser : AuthorizeAttribute
    {
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            // If Session isn't defined, user cannot be authorized
            if (httpContext.Session == null)
                return false;

            // If User isn't authenticated return false
            if (!httpContext.User.Identity.IsAuthenticated)
                return false;

            // Check which Roles if any need to be checked
            if (Roles.Contains("IST"))          // Intranet Support Team - GroupID = 261
            {
                // If user is not part of the Intranet Support Team Group, user is not authorized
                if (httpContext.Session["GroupID"] == null || httpContext.Session["GroupID"].ToString() != "261")
                    return false;
            }
            return true;

        }


        private class RedirectController : Controller
        {
            public ActionResult RedirectToSomewhere()
            {
                return RedirectToAction("Authorize", "Error");
            }
        }

        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
           
            filterContext.Result = (new RedirectController()).RedirectToSomewhere();
        }
    }

Open in new window


The failure part works because it redirects to another Controller/Action on failure.  

Here is my test:
    [TestClass]
    public class AuthorizeTest
    {
        private AuthorizeAttribute attribute;
        private AuthorizationContext authorizationContext;

        internal class FakeController : Controller
        {
            public ActionResult Nothing()
            {
                return new EmptyResult();
            }
        }

        private void SetupSession(string sessionStr = "GroupID", string value = "261")
        {
            var mockContext = Mock.Get(authorizationContext.HttpContext);
            var mockSession = new Mock<HttpSessionStateBase>();
            mockSession.SetupGet(x => x[sessionStr]).Returns(value);

            // Return the mock.
            mockContext.SetupGet(x => x.Session).Returns(mockSession.Object);
        }

        private void Authorize()
        {
            attribute.OnAuthorization(authorizationContext);
        }

        [TestInitialize]
        public void TestSetup()
        {
            attribute = new AuthUser();
            attribute.Roles = "IST";

            // Get FakeController for test
            var controller = new FakeController();
            
            // Setup Server Mock
            var server = new Mock<HttpServerUtilityBase>();

            // Setup Response Mock
            var response = new Mock<HttpResponseBase>(MockBehavior.Strict);
            response.Setup(r => r.ApplyAppPathModifier(Moq.It.IsAny<String>())).Returns((String url) => url);
            //esponse.SetupGet(r => r.Cache).Returns(HttpRuntime.Cache);

            // Setup Request Mock
            var request = new Mock<HttpRequestBase>(MockBehavior.Strict);
            request.SetupGet(r => r.UserHostAddress).Returns("127.0.0.1");
            request.SetupGet(r => r.ApplicationPath).Returns("/");
            request.SetupGet(r => r.Url).Returns(new Uri("http://localhost/", UriKind.Absolute));

            // Setup Session Mock
            var session = new Mock<HttpSessionStateBase>();
            session.Setup(s => s.SessionID).Returns(Guid.NewGuid().ToString());

            // Setup Identity 
            var identity = new GenericIdentity("DefaultUser");
            var principal = new GenericPrincipal(identity, null);

            // Mock the HttpContext
            var context = new Mock<HttpContextBase>(MockBehavior.Strict);
            context.SetupGet(c => c.Items).Returns(new Mock<IDictionary>().Object);
            context.SetupGet(c => c.Request).Returns(request.Object);
            context.SetupGet(c => c.Response).Returns(response.Object);
            context.SetupGet(c => c.Server).Returns(server.Object);
            context.SetupGet(c => c.Session).Returns(session.Object);
            context.SetupGet(c => c.Cache).Returns(HttpRuntime.Cache);
            context.SetupGet(c => c.User).Returns(principal);
            context.SetupGet(c => c.User.Identity.IsAuthenticated).Returns(true);

            // Mock the controller context (using the objects mocked above)
            ControllerContext ctx = new ControllerContext();
            ctx.HttpContext = context.Object;

            // Setup the authorizationContext
            authorizationContext = new AuthorizationContext();
            authorizationContext.Controller = controller;
            authorizationContext.HttpContext = ctx.HttpContext;

            var controllerDescriptor = new ReflectedControllerDescriptor(typeof(FakeController));
            var method = typeof(FakeController).GetMethod("Nothing");
            authorizationContext.ActionDescriptor = new ReflectedActionDescriptor(method, "Nothing", controllerDescriptor);
        }

        [TestMethod]
        public void SuccessWhenGroupIDIsIST()
        {
            // Arrange
            SetupSession("GroupID", "261");

            // Act
            Authorize();

            // Assert
            // ToDo:  THE TEST WORKS AS DESIGNED BUT CAN'T FIGURE OUT HOW TO CHECK THE RESULT SO THE TEST WILL PASS - CURRENTLY THE TEST FAILS
            Assert.AreSame(typeof(System.Web.Mvc.RedirectToRouteResult), authorizationContext.Result);
        }

Open in new window


I tried to mock the Cache but I am getting an error trying to set it up.

Any help would be greatly appreciated!
MockExceptionError.fw.png
MockCacheError.fw.png
0
Comment
Question by:dyarosh
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
5 Comments
 
LVL 75

Expert Comment

by:käµfm³d 👽
ID: 39962448
Why are you setting up the Cache property? Are you going to actually call or verify that it was called? If not, then you don't need to set it up. You only need to provide setup for those methods/properties that will be called inside the code being tested, or for which you need to ensure that the method or property was called/accessed.

The reason you get the error is because you are mixing types. r.Cache is of type HttpCachePolicyBase and HttpRuntime.Cache is of type Cache.

Be careful with having global mock objects as you should really write your tests so that no two tests interfere with each other. Doing so helps keep the things that you are testing isolated from each other by way of avoiding side effects. Myself, I create mocks within each test method, unless I can guarantee that no two tests will interfere with the others. By having distinct mocks in each test method, you ensure that no two tests will affect one another.
0
 

Author Comment

by:dyarosh
ID: 39964312
I am trying to mock the cache because the error I get when I return true from IsValid is a null reference in Response.cache.
0
 

Accepted Solution

by:
dyarosh earned 0 total points
ID: 40023472
I found a solution to my problem using this link: https://github.com/mono/aspnetwebstack/blob/master/test/System.Web.WebPages.Test/Extensions/HttpResponseExtensionsTest.cs

I created a Mock of the Cache as follows:
            // Setup Cache Mock
            var timestamp = new DateTime(2011, 1, 1, 0, 0, 0);
            var cache = new Mock<HttpCachePolicyBase>();
            cache.Setup(c => c.SetCacheability(It.Is<HttpCacheability>(p => p == HttpCacheability.Public))).Verifiable();
            cache.Setup(c => c.SetExpires(It.Is<DateTime>(p => p == timestamp.AddSeconds(20)))).Verifiable();
            cache.Setup(c => c.SetMaxAge(It.Is<TimeSpan>(p => p == TimeSpan.FromSeconds(20)))).Verifiable();
            cache.Setup(c => c.SetValidUntilExpires(It.Is<bool>(p => p == true))).Verifiable();
            cache.Setup(c => c.SetLastModified(It.Is<DateTime>(p => p == timestamp))).Verifiable();
            cache.Setup(c => c.SetSlidingExpiration(It.Is<bool>(p => p == false))).Verifiable();

I then assigned it to the HttpContextBase as follows:
context.SetupGet(c => c.Response.Cache).Returns(cache.Object);
0
 

Author Closing Comment

by:dyarosh
ID: 40031536
It only took me 28 days but I finally found the solution on my own.
0

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
JavaScript has plenty of pieces of code people often just copy/paste from somewhere but never quite fully understand. Self-Executing functions are just one good example that I'll try to demystify here.
The viewer will learn how to look for a specific file type in a local or remote server directory using PHP.
Learn how to create flexible layouts using relative units in CSS.  New relative units added in CSS3 include vw(viewports width), vh(viewports height), vmin(minimum of viewports height and width), and vmax (maximum of viewports height and width).

724 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question