Simple Question: Setup mock for ajax request in asp.net mvc - asp.net-mvc

I am new in unit test and MVC development.
I have a question for using moq for unit testing in asp.net mvc. I have a controller which accepts an ajax action:
[HttpPost,Authorize]
public ActionResult GrabLink()
{
string username = HttpContext.User.Identity.Name;
string rssUrl = Request.Params["Grablink"].ToString();
...}
This action deals with the http request which I generate from the view:
var mockRequest = new Moq.Mock<HttpRequestBase>();
but I can not find a way to define the parameters I used in the class. Also, is there any way to use the value binding provider directly to pass the value to the controller if I would like to do an ajax post?
I am a newbie in handling web request. If you have some good tutorial for better understanding the Http request (as well as the Httpcontext and related classes in asp.net) please post here. Thank you very much!

This works very well for me:
var controller = new HomeController();
var context = new Mock<HttpContextBase>(MockBehavior.Strict);
var controllerContext = new Mock<ControllerContext>();
controllerContext.SetupGet(x => x.HttpContext.User.Identity.Name)
.Returns("TestUser");
controllerContext.SetupGet(x => x.HttpContext.User.Identity.IsAuthenticated)
.Returns(true);
controllerContext.SetupGet(x => x.HttpContext.Request.IsAuthenticated)
.Returns(true);
controller.ControllerContext = controllerContext.Object;
// As a bonus, instantiate the Url helper to allow creating links
controller.Url = new UrlHelper(
new RequestContext(context.Object, new RouteData()), new RouteCollection());
This will allow you to initialize any user you want as an authenticated user, and the last line will allow you to user the Url helper within the controller even though you're calling it from a unit test.

As Scott said HttpContext makes Controllers hard to test. Anyway he's got a pretty solution at here.
BTW why didn't you make rssUrl a parameter if it is assigning by POST or GET?
e.g.
//POST: /GrabLink?rssUrl=bla bla...
[HttpPost,Authorize]
public ActionResult GrabLink(IPrincipal user, string rssUrl) {
string userName = user.Name;
}

Ok, #cem covered your second question very well.
For your first, nerddinner, and If I'm not mistaken, when you create a new Internet Application with Unit test, in Visual Studio, have the following mock classes for HttpContext. Its at the bottom of this file.
You could use these (or create a new Internet App +Tests with VS) and copy all the fake classes for your tests. (I wrote a Moq example below)
It looks like this:
public class MockHttpContext : HttpContextBase {
private IPrincipal _user;
public override IPrincipal User {
get {
if (_user == null) {
_user = new MockPrincipal();
}
return _user;
}
set {
_user = value;
}
}
public override HttpResponseBase Response
{
get
{
return new MockHttpResponse();
}
}
}
public class MockHttpResponse : HttpResponseBase {
public override HttpCookieCollection Cookies
{
get
{
return new HttpCookieCollection();
}
}
}
Not tested, but to Use mock it would look like this:
var fakeReqBase = new Mock<HttpRequestBase>();
fakeReqBase.Setup(f => f.User).Returns(new GenericIdentity("FakeUser"));
//generic identity implements IIdentity
fakeUserRepo.Object;//this returns fake object of type HttpRequestBase
Checkout the Moq Quickstart. Its quite easy to get used to, and the fluent interface really helps.

Related

Session is not working in controller when I call from unitTesting

I have ASP.NET MVC project. Now I am learning how to use UnitTesting. For this purpose I created UnitTest project.
I have below code in my Testclass :
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
Controller defaultpage = new Controller();
var result = defaultpage.defaultpage("43", "Y", "Y");
}
}
public ActionResult defaultpage(string uid, string access, string add)
{
Session["uid"] = uid;
Session["access"] = access;
Session["add"] = add;
}
Here when it comes to defaultpage controller method, it is giving Object reference not set to an instance of an object. .
How do I take session in controller when i call from UnitTest?
You have to mock session since it's not defined in the context of a unit test;
Here is a brief summary of how to mock session using c# and MOQ
http://www.syntaxsuccess.com/viewarticle/how-to-mock-httpcontext
The basics of it can be summed up with this block:
Mock<HttpContextBase> httpContext = new Mock<HttpContextBase>();
Mock<HttpSessionStateBase> session = new Mock<HttpSessionStateBase>();
session.Setup(s => s["SomeSessionKey"]).Returns(someObject);
httpContext.Setup(c => c.Session).Returns(session.Object);
Another alternative is to use NSubstitute which is a library with an api very similar to MOQ
You can't.
Your controller is working independent of the HTTP Context and HTTP pipeline that exists when visiting your ASP.NET MVC application in a hosted environment running IIS.
In this instance you'll need to look at mocking your session using a library such as Moq
Then you're able to create a mocked implementation of the HTTP context object which contains the session like so (code sample taken from this tutorial that I would recommend you take a look at):
// create the mock http context
var fakeHttpContext = new Mock();
// create a mock session object and hook it up to the mock http context
var sessionMock = new HttpSessionMock {{"selectedYear", 2013}, {"selectedMonth", 10}};
var mockSessionState = new Mock();
fakeHttpContext.Setup(ctx => ctx.Session).Returns(sessionMock);
// ... and here's how to attach a http context identity, just in case you'll come to need that, too
var fakeIdentity = new GenericIdentity("mno#ucsj.dk");
var principal = new GenericPrincipal(fakeIdentity, null);
fakeHttpContext.Setup(t => t.User).Returns(principal);
// we'll need to hook our http context up to a controller context mock - because we can't provide our controller with the http context mock directly
var homeControllerMock = new Mock();
homeControllerMock.Setup(foo => foo.HttpContext).Returns(fakeHttpContext.Object);

Difference between HttpContext and HttpContextWrapper in terms of Unit Testing and in terms of Web Forms and MVC

I know the difference between HttpContext and HttpContextWrapper is below...
HttpContext
This is the vintage asp.net context. The problem with this is that it has no base class and isn't virtual, and hence is unusable for testing (cannot mock it). It's recommended to not pass it around as function arguments, instead pass around variables of type HttpContextBase.
HttpContextBase
This is the (new to c# 3.5) replacement to HttpContext. Since it is abstract, it is now mockable. The idea is that your functions that expect to be passed a context should expect to receive one of these. It is concretely implemented by HttpContextWrapper
HttpContextWrapper
Also new in C# 3.5 - this is the concrete implementation of HttpContextBase. To create one of these in a normal webpage, use new HttpContextWrapper(HttpContext.Current).
The idea is that to make your code unit-testable, you declare all your variables and function parameters to be of type HttpContextBase, and use an IOC framework eg Castle Windsor to get it injected. In normal code, castle is to inject the equivalent of 'new HttpContextWrapper
(HttpContext.Current)', whereas in test code you're to be given a mock of HttpContextBase.
But I am not aware about its real use. I heard that it's useful in Unit Testing in comparing with Web Forms. but how it's useful ?
I also know that we can use it to execute the controller and Action as mentioned here
I heard that it's useful in Unit Testing in comparing with Web Forms. but how it's useful ?
Let's take an example of an ASP.NET MVC controller action which is adding a cookie to the response:
public class HomeController : Controller
{
public ActionResult Index()
{
var cookie = new HttpCookie("foo", "bar");
this.Response.Cookies.Add(cookie);
return View();
}
}
Notice the Response property over there. It's an HttpResponseBase. So we can mock it in a unit test:
public class HttpResponseMock: HttpResponseBase
{
private HttpCookieCollection cookies;
public override HttpCookieCollection Cookies
{
get
{
if (this.cookies == null)
{
this.cookies = new HttpCookieCollection();
}
return this.cookies;
}
}
}
public class HttpContextMock: HttpContextBase
{
private HttpResponseBase response;
public override HttpResponseBase Response
{
get
{
if (this.response == null)
{
this.response = new HttpResponseMock();
}
return this.response;
}
}
}
and now we could write a unit test:
// arrange
var sut = new HomeController();
var httpContext = new HttpContextMock();
sut.ControllerContext = new ControllerContext(httpContext, new RouteData(), sut);
// act
var actual = sut.Index();
// assert
Assert.AreEqual("bar", sut.Response.Cookies["foo"].Value);
And since all members are virtual we could use a mocking framework which would avoid us the need to write those mock classes for the unit test. For example with NSubstitute here's how the test might look:
// arrange
var sut = new HomeController();
var context = Substitute.For<HttpContextBase>();
var response = Substitute.For<HttpResponseBase>();
var cookies = new HttpCookieCollection();
context.Response.Returns(response);
context.Response.Cookies.Returns(cookies);
sut.ControllerContext = new ControllerContext(context, new RouteData(), sut);
// act
var actual = sut.Index();
// assert
Assert.AreEqual("bar", sut.Response.Cookies["foo"].Value);
Now let's take a WebForm:
protected void Page_Load(object sender, EventArgs)
{
var cookie = new HttpCookie("foo", "bar");
this.Response.Cookies.Add(cookie);
}
In this case the Response property is the concrete HttpResponse. So you are busted. Impossible to unit test in isolation.

Response Object is a null reference in my Controller's action method

I'm developing a webapp using ASP.NET MVC and C#. And I'm creating a unit test for this webapp using NUnit and Rhino Mock. My problem is that I have a Response object in my controller's action method and when I execute my unit test my test is failing because the Response object is a null reference.
Do I need to separate this Response object call in my actions or there is a better way to resolve this?
public ActionResult Login( string user, string password )
{
Response.Cookies[ "cookie" ].Value = "ck";
...
return View();
}
Please advise.
Many thanks.
What the controller really lacks is its HttpContext. In a test method it should be added explicitly if needed:
[Test]
public void TestMethod()
{
// Assume the controller is created once for all tests in a setup method
_controller.ControllerContext.HttpContext = new DefaultHttpContext();
var result = _controller.Login("username", "verySaf3Passw0rd");
// Asserts here
}
This is one of the annoying points where ASP.NET MVC is not as testable and loosely coupled as it could be. See this question for some suggestions how to mock the HTTP context objects.
I ended up creating a real response that my mock context returns like this...
Mock<HttpSessionStateBase> mockSession;
Mock<ControllerContext> mockContext;
Mock<ISessionProvider> mockSessionProvider;
HttpResponse testResponse;
MyController controller;
[TestInitialize]
public void Initialize()
{
testResponse = new HttpResponse(TextWriter.Null);
mockContext = new Mock<ControllerContext>();
mockSession = new Mock<HttpSessionStateBase>();
mockContext.Setup(x => x.HttpContext.Session).Returns(mockSession.Object);
mockContext.Setup(x => x.HttpContext.Response).Returns(new HttpResponseWrapper(testResponse));
controller = new MyController();
controller.ControllerContext = mockContext.Object;
}

asp.net mvc How to test controllers correctly

I'm having difficulty testing controllers. Original my controller for testing looked something like this:
SomethingController CreateSomethingController()
{
var somethingData = FakeSomethingData.CreateFakeData();
var fakeRepository = FakeRepository.Create();
var controller = new SomethingController(fakeRepository);
return controller;
}
This works fine for the majority of testing until I got the Request.IsAjaxRequest() part of code. So then I had to mock up the HttpContext and HttpRequestBase. So my code then changed to look like:
public class FakeHttpContext : HttpContextBase
{
bool _isAjaxRequest;
public FakeHttpContext( bool isAjaxRequest = false )
{
_isAjaxRequest = isAjaxRequest;
}
public override HttpRequestBase Request
{
get
{
string ajaxRequestHeader = "";
if ( _isAjaxRequest )
ajaxRequestHeader = "XMLHttpRequest";
var request = new Mock<HttpRequestBase>();
request.SetupGet( x => x.Headers ).Returns( new WebHeaderCollection
{
{"X-Requested-With", ajaxRequestHeader}
} );
request.SetupGet( x => x["X-Requested-With"] ).Returns( ajaxRequestHeader );
return request.Object;
}
}
private IPrincipal _user;
public override IPrincipal User
{
get
{
if ( _user == null )
{
_user = new FakePrincipal();
}
return _user;
}
set
{
_user = value;
}
}
}
SomethingController CreateSomethingController()
{
var somethingData = FakeSomethingData.CreateFakeData();
var fakeRepository = FakeRepository.Create();
var controller = new SomethingController(fakeRepository);
ControllerContext controllerContext = new ControllerContext( new FakeHttpContext( isAjaxRequest ), new RouteData(), controller );
controller.ControllerContext = controllerContext;
return controller;
}
Now its got to that stage in my controller where I call Url.Route and Url is null. So it looks like I need to start mocking up routes for my controller.
I seem to be spending more time googling on how to fake/mock objects and then debugging to make sure my fakes are correct than actual writing the test code. Is there an easier way in to test a controller? I've looked at the TestControllerBuilder from MvcContrib which helps with some of the issues but doesn't seem to do everything. Is there anything else available that will do the job and will let me concentrate on writing the tests rather than writing mocks?
Thanks
You can use some of the libraries that give you out of the box some of these objects. For example RhinoMock, NMock ... etc. I personally use Moq - it's good enough and free. What i like most in Moq is the linq expressions.
Most mocking engine will do all this for you. I use RhinoMocks but there are a lot more available. Also Moles is very new and interesting mocking engine (this generally comes with Pex which is yet more ammo in your unit testing arsenal)
MvcContrib + RhinoMocks. Check out the TestControllerBuilder in the MvcContrib.TestHelper library. Here's the official write-up: http://mvccontrib.codeplex.com/wikipage?title=TestHelper#Examples.
Here's an example of mocking a controller out for testing a UrlHelper: ASP.NET MVC: Mock controller.Url.Action
Here's a short explanation of how to use the TestControllerBuilder: http://codebetter.com/blogs/kyle.baley/archive/2008/03/19/testcontrollerbuilder-in-mvccontrib.aspx
Instead of mocking stuff, you can pass IAjaxRequest to constructor. Or make it base constructor class property (and use property injection). Or you can make your constructor implement IAjaxRequest and then apply global action filter on base constructor class that will setup IAjaxRequest.
This will help to abstract many things, including HttpContext stuff. Just don't abstract IHttpContext, abstract IUserContext, ISessionStorage, IAuthentication, IRequestDetails...
Another way is to use model binder directly on methods where you need specific information. See this post for example. You can make binder that will give you IsAjaxRequest, then you just make action to accept this parameter. Works very well because information is provided exactly to the method that needs it, not to the whole controller.

Mocking HttpContextBase with Moq

I have a unit test fixture in which I'm trying to test a ControllerAction on an ASP.NET MVC controller that's used for membership functions on a web app. I'm trying to mock the HttpContext for the tests. The ControllerAction under test actually sets properties on the HttpContext, such as Session values, Response.Cookies values, etc. This isn't all of the code, but here is a rough sample of the test that I'm trying to get to run:
[Test]
public void ValidRegistrationDataSuccessfullyCreatesAndRegistersUser()
{
var context = new Mock<HttpContextBase>() {DefaultValue = DefaultValue.Mock};
context.SetupAllProperties();
var provider = new Mock<MembershipProvider>(new object[] {context.Object});
var controller = new AccountController(context.Object, provider.Object);
// This just sets up a local FormCollection object with valid user data
// in it to use to attempt the registration
InitializeValidFormData();
ActionResult result = controller.Register(_registrationData);
Assert.IsInstanceOfType(typeof(ViewResult), result);
// Here is where I'd like to attempt to do Assertions against properties
// of the HttpContext, like ensuring that a Session object called "User"
// exists, and new auth cookie exists on the Response.Cookies collection.
// So far I've been unable to successfully check the values of those properties.
// I've been unsuccessful in getting those properties setup correctly on my
// mock object so that my ControllerAction can actually *set* their values,
// and that I can make assertions on them afterwards. The above code actually
// generates a StackOverflowException (which I've reported) on the
// context.SetupAllProperties() call. What am I doing wrong, or what do I need
// to do to be able to set and assert on those context properties?
}
Not sure what I'm doing wrong, but I'd love it if someone could point me in the right direction and show me how to setup this mock HttpContextBase object such that my controller can actually set values on its properties, and I can make assertions on those properties to ensure that my ControllerAction is doing what I need it to.
Am I approaching this the wrong way? I know that MVC Controllers have a ControllerContext that I can use to set values for Session, etc, but I can't figure out how something like that could be mocked without injecting it. Is there some way of doing that instead? (I also need to be able to pass the context in to my MembershipProvider too) Would that be a better approach?
Thanks.
I'm using a version of some code Steve Sanderson included in his Pro Asp.NET MVC book... and I'm currently having a moral dilemma whether it's okay to post the code here. How about I compromise with a highly stripped down version? ;)
So this can easily be reused, create a class similar to the one below that you will pass your controller. This will set up your mocks and set them to your controller's ControllerContext
public class ContextMocks
{
public Moq.Mock<HttpContextBase> HttpContext { get; set; }
public Moq.Mock<HttpRequestBase> Request { get; set; }
public RouteData RouteData { get; set; }
public ContextMocks(Controller controller)
{
//define context objects
HttpContext = new Moq.Mock<HttpContextBase>();
HttpContext.Setup(x => x.Request).Returns(Request.Object);
//you would setup Response, Session, etc similarly with either mocks or fakes
//apply context to controller
RequestContext rc = new RequestContext(HttpContext.Object, new RouteData());
controller.ControllerContext = new ControllerContext(rc, controller);
}
}
And then in your test method you'd just create an instance of ContextMocks and pass in the controller object you're testing:
[Test]
Public void test()
{
var mocks = new ContextMocks(controller);
var req = controller.Request;
//do some asserts on Request object
}
Seems very similar to Craig's examples, but this is with Moq v3. I have to give props to Steve Sanderson for this - I'm using this as a basis for testing all kinds of otherwise traditionally hard-to-test stuff: cookies, session, request method, querystring and more!
Here's how I do it.
public static HttpContextBase FakeHttpContext()
{
var context = new Mock<HttpContextBase>();
var request = new Mock<HttpRequestBase>();
var response = new Mock<HttpResponseBase>();
var session = new Mock<HttpSessionStateBase>();
var server = new Mock<HttpServerUtilityBase>();
var user = new Mock<IPrincipal>();
var identity = new Mock<IIdentity>();
request.Expect(req => req.ApplicationPath).Returns("~/");
request.Expect(req => req.AppRelativeCurrentExecutionFilePath).Returns("~/");
request.Expect(req => req.PathInfo).Returns(string.Empty);
response.Expect(res => res.ApplyAppPathModifier(It.IsAny<string>()))
.Returns((string virtualPath) => virtualPath);
user.Expect(usr => usr.Identity).Returns(identity.Object);
identity.ExpectGet(ident => ident.IsAuthenticated).Returns(true);
context.Expect(ctx => ctx.Request).Returns(request.Object);
context.Expect(ctx => ctx.Response).Returns(response.Object);
context.Expect(ctx => ctx.Session).Returns(session.Object);
context.Expect(ctx => ctx.Server).Returns(server.Object);
context.Expect(ctx => ctx.User).Returns(user.Object);
return context.Object;
}
This is an enhanced version of the MvcMockHelpers library released by Scott Hanselman. This is Moq 2.0 code; the syntax is slightly different in 3.

Resources