Null exception in filling a querystring by mocking framework - asp.net-mvc

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.

Related

MVC Controller inside ApiController with ControllerContext

Short story about what I am doing and why. I had been doing view to string conversion in Mvc project, but suddenly all project moved to the REST API. But I had to use razor engine to convert my view with all model data there, so I was trying to use directly from api, but it didn't work for me, so I decided to create a Mvc controller and call it directly from API, what is missing, only ControllerContext, because when I create controller directly, it appears to be null.
Here is my Api controller
public class AttachmentController : ApiController
{
[HttpGet]
public async Task<IHttpActionResult> Get(long id)
{
try
{
var mvcController = new AttachmentMvcController();
var result = await mvcController.Get();
return Ok(result);
}
catch (Exception e)
{
return InternalServerError(e);
}
}
}
and this is my Mvc Controller
public class AttachmentMvcController : Controller
{
public AttachmentMvcController(){ }
public async Task<byte[]> Get()
{
string result;
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// HERE IS MY PROBLEM, I NEED this.ControllerContext, but it is null !!!
if (ControllerContext == null)
{
// create it and do task
var factory = DependencyResolver.Current.GetService<IControllerFactory>() ?? new DefaultControllerFactory();
AttachmentMvcController controller = factory.CreateController(ctx.RequestContext, "AttachmentMvc") as AttachmentMvcController;
RouteData route = new RouteData();
route.Values.Add("action", "ActionThatUsesControllerContext"); // ActionName, but it not required
ControllerContext newContext = new ControllerContext(new HttpContextWrapper(System.Web.HttpContext.Current), route, controller);
controller.ControllerContext = newContext;
result = await controller.ActionThatUsesControllerContext(id);
}
else
{
result = await this.ActionThatUsesControllerContext(id);
}
return result;
}
private async Task<byte[]> ActionThatUsesControllerContext()
{
{....}
// here I am trying to use helper that uses that controller context
string viewAsString = ControllerContext.RenderPartialToString("MyView", requestModel);
{....}
}
}
If anyone has idea how to get that ControllerContext or any other ways to get my razor engine render view inside ApiController, please share.

simple testing ViewResult and mocking Model used in controller

Inside controller I have view which returns simple object to the view.
public ActionResult SomeAction(int?id)
{
MyModel model = new MyModel();
return View(model);
}
how can I unit test this controller in order to check ViewResult,
basically to
check if view is initialized? Basically how can I mock this MyModel
inside my unit test?
[Test]
public void Can_Open_SomeAction()
{
// controller is already set inside `SetUp` unit step.
ViewResult res = this.controller.SomeAction() as ViewResult;
Assert.IsNotNull(res);
}
Update:
public ActionResult SomeAction(int?id)
{
MyModel model = new MyModel();
this.PopulatePageCombos(id);
return View(model);
}
The way you set this up, I presume you simply want to see if the model is not null:
[Test]
public void Can_Open_SomeAction()
{
ViewResult res = this.controller.SomeAction() as ViewResult;
Assert.IsNotNull(res);
var model = result.Model as MyModel;
Assert.IsNotNull(model);
}
Mocking would only make sense in a context where you'd get that model from an underlying interface, for example if you had:
public ActionResult SomeAction(int?id)
{
MyModel model = _myModelQuerier.Fetch(id.Value);
return View(model);
}
then you could get around something like
var modelQuerierMock = MockRepository.GenerateMock<IMyModelQuerier>();
modelQuerierMock.Stub(x => x.Fetch(Arg<int>.Is.Anything)).Return(new MyModel(2, "product"));
inside your test class

unit test user.identity.getuserid asp.net mvc

I have a controller in which I am unit testing my Index action. I am having problem in unit testing User.Identity.GetUserId()
This is my controller
public ActionResult Index()
{
string userId = User.Identity.GetUserId();
DemoModel demoModel = _demoModelService.GetByUserId(userId);
MyModel myModel = new MyModel()
{
Name = demoModel.Name;
Description = demoModel.Description;
}
return View(myModel);
}
This is my Unit Test:
public void Test_Index_Action()
{
//Act
var result = controller.Index() as ViewResult;
//Assert
Assert.AreEqual("", result.ViewName);
}
When I debug my test method, as it reaches the first line of code(User.Identity.GetUserId) of my Index action, it generates null UserId. How can I access the userId in unit testing this code?
I've been struggeling with mvc unit test my self, while there are known techniques to improve testability of your mvc application, most of the projects I worked on are sadly not following them.
So I decided to start this project to help me and others who love to unit test their mvc application. Please take a look at: https://github.com/ibrahimbensalah/Xania.AspNet.Simulator.
Here is an example unit test class
using System.Web.Mvc;
using NUnit.Framework;
using Xania.AspNet.Simulator;
public class SimulatorTests
{
[Test]
public void ActionExecuteTest()
{
// arange
var controller = new TestController();
// act
var result = controller.Execute(c => c.Index());
// assert
Assert.AreEqual("Hello Simulator!", result.ViewBag.Title);
}
[Test]
public void UnAuthorizedActionTest()
{
// arrange
var controller = new TestController();
// act
var result = controller.Execute(c => c.UserProfile());
// assert
Assert.IsInstanceOf<HttpUnauthorizedResult>(result.ActionResult);
}
[Test]
public void AuthorizedActionTest()
{
// arrange
var controller = new TestController();
// act
var result = controller.Action(c => c.UserProfile()).Authenticate("user", null).Execute();
// assert
Assert.IsInstanceOf<ViewResult>(result.ActionResult);
}
}
public class TestController : Controller
{
public ActionResult Index()
{
ViewBag.Title = "Hello Simulator!";
return View();
}
[Authorize]
public ActionResult UserProfile()
{
return View();
}
}

MVC 2 simple test fails - why?

I can't find any reason for this unit test to fail, but it does every time.
HomeController.cs:
[HandleError]
public class HomeController : Controller
{
public ActionResult Index()
{
var model = "Whatever";
return View( model );
}
}
HomeControllerTest.cs:
[TestClass]
public class HomeControllerTest
{
[TestMethod]
public void Index()
{
var controller = new HomeController();
var result = controller.Index() as ViewResult;
var model = result.ViewData.Model;
Assert.IsInstanceOfType( model, typeof(string) );
}
}
result is not null, nor is result.ViewData. But result.ViewData.Model is always null.
What in the world is causing this to fail? It's such a simple test...
EDIT
This is even weirder. If I create a class, and use the class as the model, it doesn't fail. It only fails when the model is a string! i.e., this passes:
HomeController.cs:
[HandleError]
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new SomeClass
{
Name = "Whatever"
};
return View( model );
}
}
public class SomeClass
{
public string Name { get; set; }
}
HomeControllerTest.cs
[TestClass]
public class HomeControllerTest
{
[TestMethod]
public void Index()
{
var controller = new HomeController();
var result = controller.Index() as ViewResult;
var model = result.ViewData.Model;
Assert.IsInstanceOfType( model, typeof(SomeClass) );
}
}
The model is null that's why.
When you pass a string as the argument to View(string), the string is actually the view name, not a model.
Cast it as an object to use the overload for the model.
return View((object)model);
View(Object) - Creates a ViewResult object by using the model that renders a view to the response.
View(String) - Creates a ViewResult object by using the view name that renders a view.

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

Resources