how to add session to mock httpcontext? - asp.net-mvc

As per scott hanselman's mock example http://www.hanselman.com/blog/ASPNETMVCSessionAtMix08TDDAndMvcMockHelpers.aspx I tried to mock httpcontext using MockHelpers as code snippet below
controller = GetAccountController();
ActionResult result = controller.ChangePassword();
HttpContextBase hb = MvcMockHelpers.FakeHttpContext("~/Account/ChangePassword");
hb.Session.Add("id", 5);
// Assert Assert.AreEqual(5, (int)hb.Session["id"]);
I noticed that the session wasn't added and didn't receive any error either. The session object's properties had below value
Count = 0, CodePage = 0, Content = null, IsCookieLess = null, IsNewSession = null, IsReadOnly = null, IsSynchronized = null, Keys = null, LCID = 0, Mode = off, SessionId = null, Static Objects = null, SynRoot = null, TimeOut = 0
I was getting same result for Rhino mock and Moq.
Please advice me how to add session to mock httpcontext.
Thanks in advance.

Here's what I use to mock not only the session, but most other objects that you will need (request, response, etc), this code is a collection of code of Steve Sanderson and others as well as my own, note that the session is faked using a dictionary
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Web;
using System.Web.Routing;
using System.Web.Mvc;
namespace ECWeb2.UnitTests {
public class ContextMocks {
public Moq.Mock<HttpContextBase> HttpContext { get; private set; }
public Moq.Mock<HttpRequestBase> Request { get; private set; }
public Moq.Mock<HttpResponseBase> Response { get; private set; }
public RouteData RouteData { get; private set; }
public ContextMocks(Controller onController) {
// Define all the common context objects, plus relationships between them
HttpContext = new Moq.Mock<HttpContextBase>();
Request = new Moq.Mock<HttpRequestBase>();
Response = new Moq.Mock<HttpResponseBase>();
HttpContext.Setup(x => x.Request).Returns(Request.Object);
HttpContext.Setup(x => x.Response).Returns(Response.Object);
HttpContext.Setup(x => x.Session).Returns(new FakeSessionState());
Request.Setup(x => x.Cookies).Returns(new HttpCookieCollection());
Response.Setup(x => x.Cookies).Returns(new HttpCookieCollection());
Request.Setup(x => x.QueryString).Returns(new NameValueCollection());
Request.Setup(x => x.Form).Returns(new NameValueCollection());
// Apply the mock context to the supplied controller instance
RequestContext rc = new RequestContext(HttpContext.Object, new RouteData());
onController.ControllerContext = new ControllerContext(rc, onController);
onController.Url = new UrlHelper(rc);
}
ContextMocks() {
}
// Use a fake HttpSessionStateBase, because it's hard to mock it with Moq
private class FakeSessionState : HttpSessionStateBase {
Dictionary<string, object> items = new Dictionary<string, object>();
public override object this[string name] {
get { return items.ContainsKey(name) ? items[name] : null; }
set { items[name] = value; }
}
}
}
}

The code you referenced explains how you can fake out the httpcontext - it doesn't actually do anything when you call "hb.Session.Add" - it just stops the test from failing because of a dependency on the HttpContext.

You can use the MVC Contrib library provided by the Outercurve Foundation to mock session state and other objects that are available during the handling of a normal request (HttpRequest, HttpResponse...etc.).
http://mvccontrib.codeplex.com/ (or use NuGet to download it)
It contains a TestHelper library which helps you to quickly create unit tests.
For example:
[TestMethod]
public void TestSomething()
{
TestControllerBuilder builder = new TestControllerBuilder();
// Arrange
HomeController controller = new HomeController();
builder.InitializeController(controller);
// Act
ViewResult result = controller.About() as ViewResult;
// Assert
Assert.IsNotNull(result);
}
Using the TestControllerBuilder type provided by the MVC Contrib TestHelper library you can quickly initialize your controller and initialize its internal data members (HttpContext, HttpSession, TempData...).
Of course, the HttpSessionState itself is also mocked this way, so adding something to it (Session.Add) won't actually do something. As is intended, we mocked it.
Seems like you want to mock the HttpContext, but still have it setup with a working session state. Sounds like you want to do something as described here:
http://jasonbock.net/jb/Default.aspx?blog=entry.161daabc728842aca6f329d87c81cfcb

This is what i usually do
//Mock The Sesssion
_session = MockRepository.GenerateStrictMock<httpsessionstatebase>();
_session.Stub(s => s["Connectionstring"]).Return(Connectionstring);
//Mock The Context
_context = MockRepository.GenerateStrictMock<httpcontextbase>();
_context.Stub(c => c.Session).Return(_session);
var databaseExplorerController = new DatabaseExplorerController(repository);
//Assign COntext to controller
databaseExplorerController.ControllerContext = new ControllerContext(_context, new RouteData(),
_databaseExplorer);
I've written a small aricle about this at
http://www.gigawebsolution.com/Posts/Details/66/Mock-Session-in-MVC3-using-Rhino-Mock
Hope this helps

A little bit late, but this is what is use.
I''m using the MoQ framework from https://code.google.com/p/moq/
Now the session is usable in the controller implementation.
private class MockHttpSession : HttpSessionStateBase
{
readonly Dictionary<string, object> _sessionDictionary = new Dictionary<string, object>();
public override object this[string name]
{
get
{
object obj = null;
_sessionDictionary.TryGetValue(name, out obj);
return obj;
}
set { _sessionDictionary[name] = value; }
}
}
private ControllerContext CreateMockedControllerContext()
{
var session = new MockHttpSession();
var controllerContext = new Mock<ControllerContext>();
controllerContext.Setup(m => m.HttpContext.Session).Returns(session);
return controllerContext.Object;
}
[TestMethod]
public void Index()
{
// Arrange
MyController controller = new MyController();
controller.ControllerContext = CreateMockedControllerContext();
// Act
ViewResult result = controller.Index() as ViewResult;
....
}

Related

NUnit - UpdateModel issue: NullReferenceException

I have problem with testing classes, which using UpdateModel() method.
I get System.NullReferenceException.
I use NUnit.
This is my method from HomeController:
public ActionResult ProjectsEdit(Projects model)
{
var projects = db.Projects.First();
projects.Content = model.Content;
UpdateModel(projects);
db.SaveChanges();
return RedirectToAction("Projects");
}
Here is test class:
[Test]
public void ProjectsEditPostTest()
{
var routeData = new RouteData();
var httpContext = MockRepository.GenerateStub<HttpContextBase>();
//var httpContext = new FakeHttpContext("Edit");
FormCollection formParameters = new FormCollection();
ControllerContext controllerContext =
MockRepository.GenerateStub<ControllerContext>(httpContext,
routeData,
controller);
controller.ControllerContext = controllerContext;
// Act
string newContent = "new content";
Projects projects = new Projects { ID = 1, Content = newContent };
controller.ProjectsEdit(projects);
// Assert
Assert.AreEqual(newContent, controller.db.Projects.First().Content);
}
What should I do to make it works?
Just add the following line in the Assert phase:
controller.ValueProvider = formParameters.ToValueProvider();
It assigns a value provider to the controller on which the UpdateModel method relies. This value provider is associated to the FormCollection variable you have defined and which allows you to pass some values.
You may also check a similar answer which uses MvcContrib.TestHelper to simplify the Arrange phase.

Null exception in filling a querystring by mocking framework

There is a simple controller that a querystring is read in constructor of it.
public class ProductController : Controller
{
parivate string productName;
public ProductController()
{
productName = Request.QueryString["productname"];
}
public ActionResult Index()
{
ViewData["Message"] = productName;
return View();
}
}
Also I have a function in unit test that create an instance of this Controller and I fill the querystring by a Mock object like below.
[TestClass]
public class ProductControllerTest
{
[TestMethod]
public void test()
{
// Arrange
var querystring = new System.Collections.Specialized.NameValueCollection { { "productname", "sampleproduct"} };
var mock = new Mock<ControllerContext>();
mock.SetupGet(p => p.HttpContext.Request.QueryString).Returns(querystring);
var controller = new ProductController();
controller.ControllerContext = mock.Object;
// Act
var result = controller.Index() as ViewResult;
// Assert
Assert.AreEqual("Index", result.ViewName);
}
}
Unfortunately Request.QueryString["productname"] is null in constructor of ProductController when I run test unit.
Is ther any way to fill a querystrin by a mocking and get it in constructor of a control?
There is a simple controller that a querystring is read in constructor of it.
You shouldn't be doing this and such controller shouldn't exist. The controller context is not yet initialized in the constructor and it will fail not only for the unit test but in real.
You should use the Initialize method where you have access to the request context.

Mock ParentActionViewContext MVC.Net

I can't find a solution to mock ControllerContext.ParentActionViewContext.
here is the code of my controller
[ChildActionOnly]
public ViewResult Menu()
{
string controller = ControllerContext.ParentActionViewContext.RouteData.Values["controller"].ToString();
string action = ControllerContext.ParentActionViewContext.RouteData.Values["action"].ToString();
List menuItems = new List();
...code to populate my list...
return View(menuItems);
}
What I want to accomplish is mock ParentActionViewContext in a test so i can pass whatever controller and action I want to do my simulations.
I can mock the RouteData of the ControllerContext, but I can't fake the one of the parent controller.
Maybe I'm missing something obviuos.
Any help is greatly appreciated.
You're not missing anything obvious. You already discovered that the ParentActionViewContext property of the ControllerContext is not marked virtual and therefore, un-mockable. You can however, accomplish what you want by creating a ViewContext object with the values you want, adding that object to the RouteData.DataTokens dictionary with the key "ParentActionViewContext."
You can view the source code to the ControllerContext class and the implementation of the ParentActionViewContext property at http://bit.ly/ku8vR4.
Here's how I implemented this in my test:
[TestFixture]
public class SomeControllerTests
{
private PartialViewResult _result;
private Mock<HttpContextBase> _mockHttpContext;
private HttpContextBase _httpContext;
private RouteData _routeData;
private RouteData _parentRouteData;
[Test]
public void CanDoSomething()
{
SetupAnonymousUser();
SetupHttpContext();
SetupRouteData();
var controller = new FooController();
controller.ControllerContext = new ControllerContext(_httpContext, _routeData, controller);
_result = controller.Index() as PartialViewResult;
var model = _result.ViewData.Model as FooViewModel;
Assert.IsNotNull(model);
Assert.AreEqual("New", model.UserStatus);
Assert.AreEqual("21", model.PromoId);
}
private void SetupHttpContext()
{
_mockHttpContext = new Mock<HttpContextBase>();
_httpContext = _mockHttpContext.Object;
}
private void SetupRouteData()
{
SetupParentRouteData();
var viewContext = new ViewContext {RouteData = _parentRouteData};
_routeData = new RouteData();
_routeData.Values.Add("controller", "foo");
_routeData.Values.Add("action", "index");
_routeData.DataTokens["ParentActionViewContext"] = viewContext;
}
private void SetupParentRouteData()
{
_parentRouteData = new RouteData();
_parentRouteData.Values.Add("controller", "home");
_parentRouteData.Values.Add("action", "index");
}
}
Hope this helps!
Michael Ibarra

How do I moq a ISingleResult? Should I? or there is a better method?

I have an action method like this in my controller
public ActionResult Index()
{
using (NorthwindDataContext db = new NorthwindDatacontext())
{
var results = db.GetRecordSets(arg1, ....).ToList();
// use results as list
}
return View();
}
and I wanted to start making tests for it (yes, after it was built, not before... but the code was written before I started to use TDD so... )
and I figured out that adding a property such as this one to the controller
public delegate NorthwindDatacontext ContextBuilderDelegate();
public ContextBuilderDelegate ContextBuilder { get; set; }
I could add in the constructor something like this...
ContextBuilder = () => new NorthwindDatacontext();
then I could test the ActionMethod setting the ContextBuilder property with a mock of NorthwindDatacontext
var controller = new MyController();
var mockDataContext = new Mock<NorthwindDatacontext>();
controller.ContextBuilder = () => mockDataContext.Object;
But... I found no way to use this because all methods of NorthwindDatacontext use ISingleResult as returnType and I cant find the way to create an object with that interface.
I've tried this
var theResult = new List<GetRecordSetsResult>();
// fill the data structure here with the provided result...
mockDataContext.Setup(c => c. GetRecordSets()).Returns(theResult as
ISingleResult<GetRecordSetsResult>);
but it doesn't work because theResult is null when converted to ISingleResult.
Is there any way to create a ISingleResult object to test this way or I'm doing the incorrect way to do things here?
Thanks in Advance
ToList() is an extension method for IEnumerable, which is easy to mock, because it only has one member method -- GetEnumerator().
Still you might have problems mocking NorthwindDataContext class, if its methods are not virtual...
Anyways, that's how I solved a similar problem in my sandbox, hope it helps:
public class MyType
{
public virtual ISingleResult<int> ReturnSomeResult() { throw new NotImplementedException(); }
}
[TestMethod]
public void TestMethod1()
{
var mockMyType = new Mock<MyType>();
var mockSingleResult = new Mock<ISingleResult<int>>();
IEnumerable<int> someEnumerable = new int[] {1,2,3,4,5};
mockSingleResult.Setup(result => result.GetEnumerator()).Returns(someEnumerable.GetEnumerator());
mockMyType.Setup(myType => myType.ReturnSomeResult()).Returns(mockSingleResult.Object);
Assert.AreEqual(15, mockMyType.Object.ReturnSomeResult().ToList().Sum());
}
I created a class that implemented ISingleResult and just put a List in it. I am fairly new to this type of coding, so while this worked for me, use at your own risk (and if you see holes post a comment).
class SingleResult<T>:ISingleResult<T>
{
readonly List<T> _list = new List<T>();
public void Add(T item)
{
_list.Add(item);
}
#region Interface Items
public IEnumerator<T> GetEnumerator()
{
return _list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public object ReturnValue { get { return _list; } }
public void Dispose() { }
#endregion
}
This can then be used to return in part of a mock. This is how I ended up using it with Rhino Mocks:
[TestMethod]
public void TestSomething()
{
//Arrange
// Make a data context and DAL
var _ctx = MockRepository.GenerateMock<IDataClassesDataContext>();
var someDALClass = new SomeDALClass(_ctx);
User testUser = UserObjectHelper.TestUser();
SingleResult<User> userList = new SingleResult<User> { testUser };
// Indicate that we expect a call the to sproc GetUserByUserID
_ctx.Expect(x => x.GetUserByUserID(testUser.UserID)).Return(userList);
//Act
someDALClass.UpdateUser(testUser);
//Assert
Assert.IsTrue(SomeTestCondition());
}

"Inject" Request.Url.Hosts - ASP.net MVC

In my ASP.net MVC application i need to get the host of the application because I have to distinguish between multiple domains/instances.
In consideration of a good design and testability I do not want to get it like this:
public ViewResult Show(int id)
{
string host = Request.Url.Host;
....
}
Is there a possibility to "inject" it through the constructor.
What would be the cleanest solution for this problem?
You could also use some constructors for your controller like so :
public MyController() : this(DefaultHostGetter) { }
public MyController(Func<string> hostGetter)
{
this.hostGetter = hostGetter;
}
private string DefaultHostGetter() { return this.Request.Url.Host; }
the view action would be :
public ViewResult Show(int id)
{
string host = this.hostGetter();
....
}
you would then be able to test your controller by supplying a different host getter (a mock).
Maybe you don't need "injection" in this case. I think for good testability the cleanest solution will be mocking of your Request. Example (using Moq library):
var request = new Mock<HttpRequestBase>();
request.SetupGet(x => x.Url).Returns(new Uri("http://localhost/any"));
var context = new Mock<HttpContextBase>();
context.SetupGet(x => x.Request).Returns(request.Object);
var controller = new YourController();
controller.ControllerContext = new ControllerContext(context.Object, new RouteData(), controller);

Resources