Unit testing if methods find and return a view in ASP.NET - asp.net

I'm new to ASP.NET and I'm refactoring some functionalities in my MVC-structured ASP.NET application into area's. This has already lead to controller-methods not able to find their views anymore, which results in the following page:
To test if all controllers can find their views, I'd like to write some automated unit tests for this.
I have came up with the following:
[TestMethod]
public void AboutTest()
{
var controller = new HomeController();
var result = controller.About() as ViewResult;
Assert.IsNotNull(result);
}
which tests the About-method in the following code:
public class HomeController : Controller
{
public ActionResult About()
{
return View();
}
public ActionResult Contact()
{
return View("~/Views/SomeFolder/Contact.cshtml");
}
}
But even when the HomeControllers About-method can not find a view, this assert succeeds, so this does not work for me.
I have found a solution online to use use ViewEngine.FindView() here. I don't think I can use this, since in some controllers the views are referenced by a hardcoded string (see the contact method in the example controller above) instead of just returning the default view (simularly named as its method). The ViewEngine.FindView(controller.ControllerContext, "about", "about"); will then fail, but the controller-method would not.
Another solution states to use Assert.IsEqual() and check if the result.ViewName is equal to a hardcoded string (for example: "About"). Since I do not set or know the title of the views I'm expecting to get returned, this would not be a solution either.
(How) would I be able to test my application for this?

You shouldn't check for null, it will return a ViewResult even when it doesn't render.
To test whether it actually renders use AssertViewRendered from mvccontrib.
[TestMethod]
public void AboutTest()
{
var controller = new HomeController();
var result = controller.About().AssertViewRendered();
}
You can even check for a specific view like so:
result.AssertViewRendered().ForView(MVC.Your.Views.AboutView);
Or supply data like so:
controller.page().AssertViewRendered().ForView("page").WithViewData<SomeModel>();
For an interactive tutorial with lots of pictures I can recommend: http://toreaurstad.blogspot.nl/2011/09/adventures-with-mvccontrib-testhelper.html
Edit:
You might also check out Selenium to test your entire app (incl. rendering of 200 routes).

Related

WebAPI2 attribute based routing 404 with nested route

I know there are lots of (answered) questions relating to attribute-based routing, but I can't seem to find one which answers my particular scenario.
I've got a WebAPI 2 controller, with a few methods using the default routing:
public Dictionary<int, SensorModel> Get()
{
return SensorModel.List();
}
public SensorModel Get(int id)
{
return SensorModel.Get(id);
}
[HttpPost]
public SensorModel Post(SensorModel model)
{
if (model == null) throw new Exception("model cannot be null");
if (model.Id <= 0) throw new Exception("Id must be set");
return SensorModel.Update(model.Id, model);
}
These all work fine. I'm trying to create a nested route as below:
[Route("sensor/{id}/suspend")]
public SensorModel Suspend(int id, DateTime restartAt, EnSite site)
{
return SensorModel.Suspend(id, restartAt, site);
}
For which I would expect the URL to look like:
http://[application_root]/api/sensor/1/suspend?restartAt={someDateTime}&site={anInt}
Sorry, forgot to say that the actual issue is a 404!
Can anyone tell me what I'm doing wrong? I know that I can do it like this:
[Route("sensor/suspend")]
public SensorModel Suspend(int id, DateTime restartAt, EnSite site)
{
return SensorModel.Suspend(id, restartAt, site);
}
Which makes the URL:
http://[application_root]/api/sensor/suspend?id=1&restartAt={someDateTime}&site={anInt}
But a cleaner API design seems to be a nested route, I think.
Your assumption is wrong in this point:
For which I would expect the URL to look like:
http://[application_root]/api/sensor/1/suspend?restartAt={someDateTime}&site={anInt}
It should be something like below:
http://[application_root]/sensor/1/suspend?id=1&restartAt={someDateTime}&site={anInt}
When you specify an attribute based routing, it overrides the default routing architecture of ../api/.. (or whatever you specify in route.config file).
So, whenever you try to use attribute based routing, you should do something like /route_prefix_at_controller_level/route_prefix_at_method_level.

Can't use ODataQueryOptions with a (regular - not webapi) Controller derived class?

public class XYZController : Controller
{
public ActionResult Index(ODataQueryOptions<Security> options = null)
{
var xyzs= GetXYZs().AsQueryable();
var results = options == null ? xyzs: options.ApplyTo(xyzs);
return View(xyzs);
}
}
This results in "No parameterless constructor defined for this object" error.
I essentially want to pass odata compliant parameters in to a regular controller.
Can this not be done?
I temporarily (until regular controllers can use ODataQueryOptions) solved this through the use of Linq2Rest (NuGet: install-package Linq2Rest)
This quite powerful library allowed me to accomplish what I am looking for with one line of code:
using Linq2Rest;
public ActionResult Index()
{
var filteredSource = GetXYZs().AsQueryable().Filter(Request.Params);
return View(filteredSource);
}
Now you can hit this Controller's Index Action like this:
xyz.com?$filter=something eq 'foo' and another gt 3&$orderby another
ODataQueryOptions<T> is only supported with web API now. That said, this is an interesting scenario. I have opened this issue on codeplex to track it.

Verify method calls on items in a collection with Moq

My problem is NOT trying to simply verify whether a method was called or not. Instead, I have a method that works on a collection of objects and I want to verify that a method on all of the collection items is being called.
Use the example of a plug-in model where I have a plug-in manager that contains a collection of plug-in objects. Each plug-in subclasses the PlugIn abstract base class which exposes an abstract Initialize method. In my test I want to make sure that Initialize is called on every plug-in regardless of whether one of them throws an exception (just part of a larger test suite).
My initial approach was to create a collection of mocked plug-ins, then configure the class under test (PlugInManager) to use the mocked objects. I then perform the test by calling PlugInManager.DoWork() which should iterate through the collection, calling DoWork() on each item.
The full test codes is as follows:
[TestMethod()]
public void MyTest()
{
// ARRANGE
var testParameter = new Something();
var mockPlugIns = new Collection<Mock<PlugIn>>()
{
new Mock<PlugIn>(),
new Mock<PlugIn>(),
new Mock<PlugIn>()
};
var plugIns = new Collection<PlugIn>();
foreach (var plugIn in mockPlugIns)
plugIns.Add(plugIn.Object);
var testManager = new PlugInManager()
{
PlugIns = plugIns
};
// ACT
testManager.DoWork(testParameter);
// ASSERT
foreach (var mockPlugIn in mockPlugIns)
mockPlugIn.Verify(plugin => plugin.DoWork(testParameter), Times.Once());
// Also tried using It.IsAny<Something>()
}
public abstract class PlugIn
{
abstract void DoWork(Something something);
}
public sealed class PlugInManager
{
public IEnumerable<PlugIn> PlugIns { get; set; }
public void DoWork(Something something)
{
foreach (var plugIn in PlugIns)
plugIn.DoWork(something);
}
}
Unfortunately, Verify fails for every item.
I've stepped through the code and see that it actually is working correctly and the Initialize method is being called on every item. When, then, is Verify failing???
UPDATE #1
I've updated the post to show the entire test method in one block. I've also changed the method to require a parameter as is the case in my real code (now).
UPDATE #2
The error I receive when running the test is:
Moq.MockException:
Expected invocation on the mock once, but was 0 times: plugin => plugin.DoWork(It.IsAny<Something>())
No setups configured.
No invocations performed.
As mentioned, when I step through the unit test I see that each of the plugins are actually being called. For some reason, however, Moq doesn't seem to be registering it or recognizing it.
UPDATE #3
After playing with the test code more, I discovered that I could make the test pass with a simple change. The test passes if I replace the foreach loop in the middle of the method with the following:
plugIns.Add(mockPlugIns[0]);
plugIns.Add(mockPlugIns[1]);
plugIns.Add(mockPlugIns[2]);
I don't see how this is making a difference and would ultimately like to make the number of items dynamic so the tests aren't always testing the case when there are three, so using the foreach is really what I need.
Any ideas?
This is actually not true and upon further testing this morning, I find that everything is working fine with the original foreach loop. I have no idea what changed but I tried many different variations late last night and while the code I have this morning looks just like what is posted, for whatever reason, the test is now passing!?!?!?!?
This worked for me in LINQPad with Moq 4. The only thing I changed was adding the parentheses on Times.Once().
void Main()
{
var MockPlugIns = new Collection<Mock<PlugIn>>()
{
new Mock<PlugIn>(),
new Mock<PlugIn>(),
new Mock<PlugIn>()
};
var plugIns = new Collection<PlugIn>();
foreach (var mockPlugIn in MockPlugIns)
plugIns.Add(mockPlugIn.Object);
var testManager = new PlugInManager()
{
PlugIns = plugIns
};
testManager.Initialize();
foreach (var mockPlugIn in MockPlugIns)
mockPlugIn.Verify(plugin => plugin.Initialize(), Times.Once());
}
public abstract class PlugIn
{
public abstract void Initialize();
}
public class PlugInManager
{
public void Initialize()
{
foreach (var plugIn in PlugIns)
{
plugIn.Initialize();
}
}
public Collection<PlugIn> PlugIns { get; set; }
}
UPDATE
I ran your updated test code, and it passed given the following implementation:
public class PlugInManager
{
public void DoWork(Something s)
{
foreach (var plugIn in PlugIns)
{
plugIn.DoWork(s);
}
}
public Collection<PlugIn> PlugIns { get; set; }
}
It passed with or without the It.IsAny change you mentioned. One initial thought was that you might not have been passing the same instance of Something to the plug-ins, but It.IsAny would have resolved that.
In short, it appears that you are doing everything right in the tests. Perhaps the issue is in the actual implementation.
Please post your implementation of PlugInManager.DoWork and the exact error message you get when the test fails. Also, what version of Moq are you using?
UPDATE
I cut-and-pasted your code and tried it. I had to make one change: abstract void DoWork on abstract class PlugIn needs to be public. After making that change it compiles and the test passes. If I comment out the "ACT" portion of your test, it fails with the error message you saw (as I would expect).
Something is different in your project or environment. I'm running .NET 4 (not Mono) under Windows 64 with Moq 4.0. Everything you have posted is correct. I would suggest confirming that you're running the latest binary of Moq, checking your project references, and trying some very simple verification tests to insure that Moq is working.

Multiple controllers, one view, and one model ASP.NET MVC 3

I want to have one model & view that is served by multiple controllers in my ASP.NET MVC 3 app.
I'm implementing a system that interacts with the users' online calendar and I support Exchange, Google, Hotmail, Yahoo, Apple, ect... Each of these has wildly different implementations of calendar APIs, but I can abstract that away with my own model. I'm thinking that by implementing the polymorphism at the controller level I will be able to deal cleanly with the different APIs and authentication issues.
I have a nice clean model and view and I've implemented two controllers so far that prove I can read/query/write/update to both Exchange and Google: ExchangeController.cs and GoogleController.cs.
I have /Views/Calendar which contains my view code. I also have /Models/CalendarModel.cs that includes my model.
I want the test for which calendar system the user is using to happen in my ControllerFactory. I've implemented it like this:
public class CustomControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == typeof(CalendarController))
{
if(MvcApplication.IsExchange) // hack for now
return new ExchangeController();
else
return new GoogleController();
}
return base.GetControllerInstance(requestContext, controllerType);
}
}
and in my Application_Start:
ControllerBuilder.Current.SetControllerFactory(new CustomControllerFactory());
This works. If I got to http://.../Calendar this factory code works and the correct controller is created!
This worked beautifully and I did it without really understanding what I was doing. Now i think I got it but I want to make sure I'm not missing something. I really spent time searching for something like this and didn't find anything.
One thing that concerns me is that I figured I'd be able to have an inheritance relationship between CalendarController and ExchangeController/GoogleController like this:
public class ExchangeController : CalendarController
{
But if I do that I get:
The current request for action 'Index' on controller type 'GoogleController' is ambiguous between the following action methods:
System.Web.Mvc.ViewResult Index(System.DateTime, System.DateTime) on type Controllers.GoogleController
System.Web.Mvc.ActionResult Index() on type Controllers.CalendarController
Which bums me out because I wanted to put some common functionality on the base and now I guess I'll have to use another way.
Is this the right way to do have multiple controllers for one view/model? What else am I going to have to consider?
EDIT: More details on my impl
Based on the responses below (thanks!) I think I need to show some more code to make sure you guys see what I'm trying to do. My model is really just a data model. It starts with this:
/// <summary>
/// Represents a user's calendar across a date range.
/// </summary>
public class Calendar
{
private List<Appointment> appointments = null;
/// <summary>
/// Date of the start of the calendar.
/// </summary>
public DateTime StartDate { get; set; }
/// <summary>
/// Date of the end of the calendar
/// </summary>
public DateTime EndDate { get; set; }
/// <summary>
/// List of all appointments on the calendar
/// </summary>
public List<Appointment> Appointments
{
get
{
if (appointments == null)
appointments = new List<Appointment>();
return appointments;
}
set { }
}
}
Then my controller has the following methods:
public class ExchangeController : Controller
{
//
// GET: /Exchange/
public ViewResult Index(DateTime startDate, DateTime endDate)
{
// Exchange specific gunk. The MvcApplication._service thing is a temporary hack
CalendarFolder calendar = (CalendarFolder)Folder.Bind(MvcApplication._service, WellKnownFolderName.Calendar);
Models.Calendar cal = new Models.Calendar();
cal.StartDate = startDate;
cal.EndDate = endDate;
// Copy the data from the exchange object to the model
foreach (Microsoft.Exchange.WebServices.Data.Appointment exAppt in findResults.Items)
{
Microsoft.Exchange.WebServices.Data.Appointment a = Microsoft.Exchange.WebServices.Data.Appointment.Bind(MvcApplication._service, exAppt.Id);
Models.Appointment appt = new Models.Appointment();
appt.End = a.End;
appt.Id = a.Id.ToString();
...
}
return View(cal);
}
//
// GET: /Exchange/Details/5
public ViewResult Details(string id)
{
...
Models.Appointment appt = new Models.Appointment();
...
return View(appt);
}
//
// GET: /Exchange/Edit/5
public ActionResult Edit(string id)
{
return Details(id);
}
//
// POST: /Exchange/Edit/5
[HttpPost]
public ActionResult Edit(MileLogr.Models.Appointment appointment)
{
if (ModelState.IsValid)
{
Microsoft.Exchange.WebServices.Data.Appointment a = Microsoft.Exchange.WebServices.Data.Appointment.Bind(MvcApplication._service, new ItemId(appointment.Id));
// copy stuff from the model (appointment)
// to the service (a)
a.Subject = appointment.Subject
...
a.Update(ConflictResolutionMode.AlwaysOverwrite, SendInvitationsOrCancellationsMode.SendToNone);
return RedirectToAction("Index");
}
return View(appointment);
}
//
// GET: /Exchange/Delete/5
public ActionResult Delete(string id)
{
return Details(id);
}
//
// POST: /Exchange/Delete/5
[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(string id)
{
Microsoft.Exchange.WebServices.Data.Appointment a = Microsoft.Exchange.WebServices.Data.Appointment.Bind(MvcApplication._service, new ItemId(id));
a.Delete(DeleteMode.MoveToDeletedItems);
return RedirectToAction("Index");
}
So it's basically the typical CRUD stuff. I've provided the sample from the ExchangeCalendar.cs version. The GoogleCalendar.cs is obviously similar in implementation.
My model (Calendar) and the related classes (e.g. Appointment) are what get passed from controller to view. I don't want my view to see details of what underlying online service is being used. I do not understand how implementing the Calendar class with an interface (or abstract base class) will give me the polymorphism I am looking for.
SOMEWHERE I have to pick which implementation to use based on the user.
I can either do this:
In my model. I don't want to do this because then my model gets all crufty with service specific code.
In the controller. E.g. start each controller method with something that redirects to the right implementation
Below the controller. E.g. as I'm suggesting above with a new controller factory.
The responses below mention "service layer". I think this is, perhaps, where I'm off the rails. If you look at the way MVC is done normally with a database, the dbContext represents the "service layer", right? So maybe what you guys are suggesting is a 4th place where I can do the indirection? For example Edit above would go something like this:
private CalendarService svc = new CalendarService( e.g. Exchange or Google );
//
// POST: /Calendar/Edit/5
[HttpPost]
public ActionResult Edit(MileLogr.Models.Appointment appointment)
{
if (ModelState.IsValid)
{
svc.Update(appointment);
return RedirectToAction("Index");
}
return View(appointment);
}
Is this the right way to do it?
Sorry this has become so long-winded, but it's the only way I know how to get enough context across...
END EDIT
I wouldn't do it this way. As Jonas points out, controllers should be very simple and are intended to coordinate various "services" which are used to respond to the request. Are the flows of requests really all that different from calendar to calendar? Or is the data calls needed to grab that data different.
One way to do this would be to factor your calendars behind a common calendar interface (or abstract base class), and then accept the calendar into the controller via a constructor parameter.
public interface ICalendar {
// All your calendar methods
}
public abstract class Calendar {
}
public class GoogleCalendar : Calendar {}
public class ExchangeCalendar : Calendar {}
Then within your CalendarController,
public class CalendarController {
public CalendarController(ICalendar calendar) {}
}
This won't work by default, unless you register a dependency resolver. One quick way to do that is to use NuGet to install a package that sets one up. For example:
Install-Package Ninject.Mvc3
I think this would be a better architecture. But suppose you disagree, let me answer your original question.
The reason you get the ambiguous exception is you have two public Index methods that are not distinguished by an attribute that indicates one should respond to GETs and one to POSTs. All public methods of a controller are action methods.
If the CalendarController isn't meant to be instantiated directly (i.e. it'll always be inherited), then I would make the Index method on that class protected virtual and then override it in the derived class.
If the CalendarController is meant to be instantiated on its own, and the other derived classes are merely "flavors" of it, then you need to make the Index method public virtual and then have each of the derived classes override the Index method. If they don't override it, they're adding another Index method (C# rules, not ours) and you need to distinguish them for MVC's sake.
I think you're on a dangerous path here. A controller should generally be as simple as possible, and only contain the "glue" between e.g. your service layer and the models/views. By moving your general calendar abstractions and vendor specific implementations out of the controllers, you get rid of the coupling between your routes and the calendar implementation.
Edit: I would implement the polymorphism in the service layer instead, and have a factory class in the service layer check your user database for the current user's vendor and instantiate the corresponding implementation of a CalendarService class. This should eliminate the need for checking the calendar vendor in the controller, keeping it simple.
What I mean by coupling to the routes is that your custom URLs is what is currently causing you problems AFAICT. By going with a single controller and moving the complexity to the service layer, you can probably just use the default routes of MVC.
As the other answers suggest, you really should refactor your code so as to not require the multiple controllers in the first place.
However, you can still have your controllers inherit from a base class controller - you simply need to make sure that when you register the routes in the Global.asax.cs, you use the overload that specifies which namespace to find the controllers and action methods for a given route
e.g.
routes.MapRoute(null, "{controller}/{action}", new[] { "Namespace.Of.Controllers.To.USe" });

NVelocity extension method ASP.NET webform

I was wondering if it's possible to use an extension method with asp.net webforms and nvelocity. I would like to set some defaults if the string value is null or empty.
Example of .vm file:
Example of my email body...
Billable Status: $billableStatus.Evaluate()
rest of my email body...
Attempted extension method:
public static class Helper
{
public static string Evaluate(this string value)
{
if (String.IsNullOrEmpty(value))
return "Not Provided";
else
return value;
}
}
Or is there an alternative to what I'm tryting to accomplish?
I don't think NVelocity can resolve extension methods with C#/VB.NET syntax sugar. What I do is register an instance of a helper in the velocity context:
var context = VelocityContext();
context.Put("helper", new Helper());
context.Put("billableStatus", "something");
...
and then in your template:
$helper.Evaluate($billableStatus)
You have to make your helper non-static for this to work, of course.
I came across something similar in past and I was looking for something more sophisticated and with more control. I found that NVelocity does provide a way to intercept the method and property calls but for that you will have to implement certain things. In order to make your custom interceptor you will need to implement NVelocity.IDuck. For example
public class MyClass : NVelocity.IDuck
{
public object GetInvoke(string propName)
{
....
}
public object Invoke(string method, params object[] args)
{
....
}
public void SetInvoke(string propName, object value)
{
....
}
}
Now any instance of MyClass will intercept and pass the method and property calls to our these three function implementation and give us a chance to resolve and return the output. You may notice from these three function signatures that in order to implement them we may need some reflection where we can locate respective methods on available extension types and execute them. If needed you can read following blog post for more details about going this way. NVelocity and extension methods

Resources