How Add test cookie to Request in C# unit test

Alma picture Alma · Jan 14, 2017 · Viewed 9.6k times · Source

How I can add test cookie to request so I can test my code from Unit test. Consider a code like this:

public ActionResult Dashboard()
{
    if (Request.Cookies["usercookie"] == null)
    {
        return RedirectToAction("Index");
    }
    return View();
}

I mock everything, but I don't know how I can add something to cookie so this line Request.Cookies["usercookie"] not return null. As now it is null and returning me this error:

{"Object reference not set to an instance of an object."}

This is one of my unit test methods:

[TestMethod]
[TestCategory("Unit")]
public void Login_ShouldValidateUserAndLoginSuccessfully()
{
    using (var kernel = new NSubstituteMockingKernel())
    {
        // Setup the dependency incjection
        kernel.Load(new EntityFrameworkTestingNSubstituteModule());

        // Create test request data 
        var request = new LogInRequest { UserName = "test", Password = "test" };

        var fakeResponseHandler = new FakeResponseHandler();
        fakeResponseHandler.AddFakeResponse(new Uri("http://localhost/test"), new HttpResponseMessage(HttpStatusCode.OK));
        ConfigurationManager.AppSettings["SearchApiBaseUrl"] = "http://test/internal";
        var server = new HttpServer(new HttpConfiguration(), fakeResponseHandler);
        var httpClient = new HttpClient(server);

        var fakeCookieManager = new FakeCookieManager();
        var authenticationService = Substitute.For<IAuthenticationService>();
        var newUser = Fake.GetNewUser(1);
        var newUserClaim = Fake.GetNewUserClaim(1, newUser.Id, "http://test/identity/claims/loans");
        authenticationService.GetUserByEmailPasswordAsync(request.UserName, request.Password).Returns(newUser);
        authenticationService.GetUserClaimByEmailAndPasswordAsync(request.UserName, request.Password).Returns(newUserClaim);
        var controller = new HomeController(httpClient, fakeCookieManager, null, authenticationService);
        Fake.SetFakeAuthenticatedControllerContext(controller);
        controller.HttpContext.Session["ReturnUrl"] = "/search"; 
        var result = controller.Login(request);
        Assert.IsNotNull(result);
    }
}

This is a class in Fake for Httpcontext:

    public static HttpContextBase InitialiseFakeHttpContext(string url = "")
    {
        var HttpContextSub = Substitute.For<HttpContextBase>();
        var RequestSub = Substitute.For<HttpRequestBase>();
        var ResponseSub = Substitute.For<HttpResponseBase>();
        var serverUtilitySub = Substitute.For<HttpServerUtilityBase>();
        var itemsSub = Substitute.For<IDictionary>();
        HttpContextSub.Request.Returns(RequestSub);
        HttpContextSub.Response.Returns(ResponseSub);
        HttpContextSub.Server.Returns(serverUtilitySub);
        var cookie = Substitute.For<HttpResponseBase>();
        HttpContextSub.Response.Returns(cookie);
        return HttpContextSub;
    }

Answer

Nkosi picture Nkosi · Jan 14, 2017

Here is an example unit test where a cookie is set on the request.

Used NSubstitute framework to mock the http context and then setup the request cookies property. Applied the mocked http context to the controller context to simulate a request.

[TestClass]
public class MyControllerTests {
    [TestMethod]
    public void Request_Cookies_Should_Not_Be_Null() {
        //Arrange
        var cookies = new HttpCookieCollection();
        cookies.Add(new HttpCookie("usercookie"));

        var mockHttpContext = Substitute.For<HttpContextBase>();
        mockHttpContext.Request.Cookies.Returns(cookies);

        var sut = new MyController();
        sut.ControllerContext = new ControllerContext {
            Controller = sut,
            HttpContext = mockHttpContext
        };

        //Act
        var result = sut.Dashboard() as ViewResult;

        //Assert
        Assert.IsNotNull(result);
    }

    public class MyController : Controller {
        public ActionResult Dashboard() {
            if (Request.Cookies["usercookie"] == null) {
                return RedirectToAction("Index");
            }
            return View();
        }
    }
}

Update:

Here is an updated version of the test using a manually created mocked HttpContext.

[TestClass]
public class MyControllerTests {
    [TestMethod]
    public void Request_Cookies_Should_Not_Be_Null() {
        //Arrange
        var cookies = new HttpCookieCollection();
        cookies.Add(new HttpCookie("usercookie"));

        var mockHttpContext = new MockHttpContext(cookies);

        var sut = new MyController();
        sut.ControllerContext = new ControllerContext {
            Controller = sut,
            HttpContext = mockHttpContext
        };

        //Act
        var result = sut.Dashboard() as ViewResult;

        //Assert
        Assert.IsNotNull(result);
    }

    public class MyController : Controller {
        public ActionResult Dashboard() {
            if (Request.Cookies["usercookie"] == null) {
                return RedirectToAction("Index");
            }
            return View();
        }
    }


    private class MockHttpContext : HttpContextBase {
        private readonly MockRequest request;
        public MockHttpContext(HttpCookieCollection cookies) {
            this.request = new MockRequest(cookies);
        }

        public override HttpRequestBase Request {
            get {
                return request;
            }
        }

        public class MockRequest : HttpRequestBase {
            private readonly HttpCookieCollection cookies;
            public MockRequest(HttpCookieCollection cookies) {
                this.cookies = cookies;
            }

            public override HttpCookieCollection Cookies {
                get {
                    return cookies;
                }
            }
        }

    }
}