Saturday 17 September 2011

Simple access of embedded resources in DLLs in MVC views

I was working with embedded views in a DLL in a MVC Razor 3 project today and I had to be able to refer to embedded Javascript .js files, images (jpg and png) and css files in the precompiled views. To make this work I tagged the files as Embedded Resource in my project, compiled the project into a dll and in the other mvc project which used the dll I could get it to fetch the embedded resources easily adding a new MVC controller action.

The mvc controller action looks like this:

The code below goes into the Home controller, ContentFile action method, which
returns a FileStreamResult below.



public FileStreamResult ContentFile(string id)
{
string resourceName = Assembly.GetExecutingAssembly().GetManifestResourceNames().ToList().FirstOrDefault(f => f.EndsWith(id));
return new FileStreamResult(Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName), GetMIMEType(id));
}

private string GetMIMEType(string fileId)
{
if (fileId.EndsWith(".js"))
{
return "text/javascript";
}
else if (fileId.EndsWith(".css"))
{
return "text/stylesheet";
}
else if (fileId.EndsWith(".jpg"))
{
return "image/jpeg";
}
return "text";
}


To use this in the views, write this:



<script type="text/javascript" src="/Home/ContentFile/test.js">
</script>

<link rel="Stylesheet" href="/Home/ContentFile/blue.css">

<img src="/Home/ContentFile/forest.jpg" />



To load up an embedded resource we look into the executing dll, which instead should perhaps load a specified assembly if necessary, and then GetManifestResourceStream and retrieving the matching resource name passed in. The MIME type must be set and is resolved by looking at the resource name passed in.

So the morale is that if you want to load a content file from a DLL in a MVC view, use a controller action and return a FileStreamResult and then load up the content file by writing the route to the ContentFile action.

Monday 12 September 2011

Testing out the WatiN unit testing

WatiN, or "Web application testing in .Net", is based on a similar package for Ruby on Rails called WatiR. This is a browser automation package that gives the ability to run say a MsTest where you open up an url in Internet Explorer 6,7,8 or 9 or Firefox 2 or 3, then locate a gui element in a web page by its id and write in some text, if it is textbox and click a button. This is making it possible easily write GUI tests for web applications running in an IE or FireFox environment, covering most users. WatiN also gives logging options and makes it possible to create screenshots and so on.

Lets start with a equivalent "Hello world" unit test using WatiN.

First off, create a new Mvc 3 Web Application, select Internet Application as the template, choose to add a unit test. Check that you got Nuget insstalled.

Then write in the Nuget console:


Install-Package WatiN


This will download the necessary DLL files to the unit test project and add to its references. These DLL files are:



  • Interop.SHDocVw - Mark in the references this DLL and choose Embed Interop Types to false.


  • WatiN.Core


  • WatinUnitTest



Now add a unit test or basic unit test and then write the following test method
inside your test class:



[TestMethod]
public void TestLogInToMrs()
{
string targetServer = "http://mrx.hex.no";
using (var browser = new IE(targetServer))
{

LogintoCerebralParese(targetServer, browser);
}
}

private static void LogintoCerebralParese(string targetServer, IE browser)
{
browser.ShowWindow(WatiN.Core.Native.Windows.NativeMethods.WindowShowStyle.ShowMaximized);
browser.Link(l => l.Url == targetServer + "/CerebralPareseRegister").Click();
browser.TextField(t => t.Name == "ctl00$ContentPlaceHolderMain$RoleComboBox").SetAttributeValue("readonly", "");
browser.TextField(t => t.Name == "ctl00$ContentPlaceHolderMain$RoleComboBox").TypeText("Registeransvarlig");
browser.Button("ContentPlaceHolderMain_LoginButton").Click();
}



In this example, an instance of an IE object is instantiated inside the using block. The url specified in the constructor argument is requested. Then the unit test
maximizes the window, then it will search on the login page for a Link object (basically searching for the A tags) by url matching CerebralPareseRegister.
It will then look for a TextField, again using a lambda overload (Linq is supported in WatIN, which is written in C#), overriding its readonly html property using the SetAttributeValue method and setting readonly to empty string, unlocking the readonly textbox. Then it writes in "Registeransvarlig" (a role in my test scenario) in the textfield, using the TypeText method with the argument passed into the text box. The last line looks for a button, i.e. an input tag element with id equal to the passed in argument and invokes the click method which will click the button.

The test then will check that it is possible to login to this registry. Without giving out to much details to our global audience, we got web registries which there will be about 50 registries later and this single test will test logging into a single registry (CerebralPareseRegistry). We would then probably test all 50 registries and verify that we can log in to the different registries. The Internet Explorer browser is not thread safe and therefore there is a risk that unit tests running in parallel will crash the IE browser. The good thing then, is that when using the IE browser in these parallel tests, they will run in STA (Single thread apartment) and therefore it will avoid the possible crash. An optimization is in the TestInitialize method use the same IE object and then dispose it in the TestComplete method. Instead, use a single IE object per test to keep thread safety. This will increase the test time. The good thing is that these automated web gui tests can be run in automatic mode and for example runned every night in the nightly build. The WatiN framework makes it therefore possible to do full integration unit tests using browser automation so that you can verify that the web application is working for the end user for its core functionality, such as log in to a web application, perform a search and so on.

The WatiN tests should be testing the core end-user functionality. The different parts of your web application, for example a MVC 3 application, should also have unit tests of their own.

As I have suggested in previous posts, the MvcContrib TestHelper should be used when testing Controllers and their actions in MVC 3. Unit tests in javascript can use the helper class of Stephen Walther. The views can also use the Razor Single File Generator to tests their views. Finally testing the DAL layer Entity Framework supports testing POCO objects using the Seed function if you use Entity Framework Objects.

WatiN supports a multitude of functionality and this blogpost just wanted to mention it.

Check out the http://watin.org website to see the documentation of WatiN and download the package, if you do not want to use Nuget. WatiN is open source and therefore fully customizable.

Wednesday 7 September 2011

Adventures with the MvcContrib TestHelper

Unit testing a MVC Controller
When unit testing a MVC controller, stop reinventing the wheel and take a look at the MvcContrib TestHelper. Add a reference to the MvcContrib.TestHelper.dll and unit testing different functionality of your controller and its actions should be a walk in the park. Yes, using Moq to build up a mocked object is possible, but since MvcContrib TestHelper supports much of the needed functionality, why not start using it?

How to start using the MvcContrib TestHelper?
Download the MvcContrib TestHelper with the MvcContrib release package from this location: Mvc Contrib

Install the MVC contrib zipped file. Actually there is no installer, just a bunch of DLL files. It is the file MvcContrib.TestHelper.dll that you are interested in. Add this dll as a reference to the Visual Studio 2010 test project in your solution (remember to add this file to your solution by saying "Copy to output folder" and modify your WiX scripts, if needed), then create a new basic unit test or unit test and at the top add the using statement:


using MvcContrib.TestHelper;



Verify that the view result is returned and view name and model type matches in a unit test for a MVC action


Given that we have modified the Index mvc view to be strongly typed by a class Bird in our Models folder, the following code can verify in a single assertion that the returned ActionResult is a ViewResult, that the rendered view name is "Index" and that the model, that is the strongly type that the view is associated with is a given type as follows:


[TestMethod]
public void IndexTestViewResult()
{
var controller = new HomeController();
ActionResult result = controller.Index();
result.AssertViewRendered().ForView("Index").WithViewData();
}



First off, I just new my controller I want to test, HomeController in this case.
Then using the extension methods in MvcContrib.TestHelper I call AsserViewRendere() which just asserts that ActionResult is of type ViewResult. Further, I check with the ForView extension method (take note of the chaining going on here) that the view name is Index. The third part of this single assert checks that the View data is of type Bird.

In this particular example, make note that my Index method looks like the following in my HomeController:


public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";

return View("Index", new Bird { SpeciesName = "Crow",
CanFly = true, WeightInGrams = 400, WingspanInCentimetres = 80 });
}

.
.
.

}


Obviously the Bird class is just a simple sample in this case.. The second argument
could be assigned to variable called model and passed in for cleaner code. The point I want to make here is that when you return a ViewResult, specifically specify the View Name explicitly, as this then can be verified with the ForView extension method in a unit test.

For more advanced controller tests there are lots of functionality in MvcTestContrib.TestHelper DLL to help out. Do not reinvent the wheel to get started with unit testing your controllers, use MvcContrib TestHelper!

Towards more complex controller action tests in MVC


Just to get started with a custom HttpContext, I wanted to test out the TestControllerBuilder class in MvcContrib.TestHelper. With this class, I adjust the unit test for the index action method a bit:


[TestMethod]
public void IndexTestViewResult()
{
TestControllerBuilder builder = new TestControllerBuilder();
var controller = builder.CreateController();
builder.HttpContext.Cache["test"] = "test1";
builder.InitializeController(controller);
ActionResult result = controller.Index();
result.AssertViewRendered().ForView("Index").WithViewData();
}


Now, I use the TestControllerBuilder class to create a controller of type HomeController. The builder is then tested out with setting the HttpContext.Cache to a test key-value pair. Further on, the line above instantiates the HomeController by using the CreateController static generic factory method by passing in the home controller as a generic type argument. Then the controller is initialized with the TestControllerBuilder. The unit test passes. Obviously, this just show how the HttpContext can be mocked using the TestControllerBuilder.

One important note here is the strange error I got thrown at me when running the test the first time.

Test method TestMvcContribUnitTests.Tests.Controllers.HomeControllerTest.IndexTestViewResult threw exception:
System.InvalidOperationException: Unable to create a factory. Be sure a mocking framework is available.


To avoid this error and get the test to pass, add also a reference to a mocking framework. By glancing into the code at the Mvc Contrib Codeplex page, I see that Rhino Mocks and Moq is the two mocking frameworks with support for TestHelper in MvcContrib. Since I have worked most with Moq, I just added a reference to Moq.dll (copy a reference to the Moq.dll assembly file, copy local set to true), and then the test passed.

This now, shows how to get a HttpContext which can be adjusted (Request, Response, Cache and so on), using Moq and MvcContrib TestHelper. The developer can then focus on the task at hand when it comes to unit test, namely to write efficiently unit tests that are relevant and not reinvent the wheel to get HttpContext up and running in Moq, without using MvcContrib TestHelper.

I will look into additional adventures of using MvcContrib TestHelper. If there are other use-case scenarios that should be presented, it would be nice to know.



Testing a RedirectToAction inside a mvc controller action


To test the redirection of an action inside a mvc controller action, use the
following:

Suppose we have return the following:


..
return RedirectToAction("About");
..


The test can then verify that we are returning a RedirectToActionResult and that
the controller action's name is "About" as follows:


..
result.AssertActionRedirect().ToAction("About");
..


In case we return a RedirectToActionResult with overload:


..
return RedirectToAction("About", "Home");
..


To test this we can write:


..
result.AssertActionRedirect().ToController("Home").ToAction("About");
..


Testing the routing in an MVC application


To test out the routes in your MVC application, the following unit test is served as an example using MvcContrib TestHelper:



[TestMethod]
public void RouteTestHomeIndex()
{
var routeTable = RouteTable.Routes;
routeTable.Clear();
routeTable.MapRoute(null, "{controller}/{action}/{id}",
new { controller= "Home", action= "Index",
id = UrlParameter.Optional });

"~/Home/Index".ShouldMapTo(action => action.Index());
"~/Home/About".ShouldMapTo(action => action.About());
}



First line of the unit tests grabs a reference to the RouteTable.Routes property, defined in the System.Web.Routing namespace. The routetable is then cleared and then
the MapRoute method adds a route definition to test. We set up the default route using the MapRoute method. Then we test the two routes "~/Home/Index" and "~/Home/About". These two values are strings and MvcContrib TestHelper has extension method which will check that the route specified in the string maps to a controller using the ShouldMapTo extension method with a generic argument specifying the controller, and in the parameter the action method of the contorller is specifed. Actually, controller => controller.Index is probably a better lambda argument here.

This shows that testing out routes are simple using MvcContrib TestHelper. Just use the string extension methods to test out which controller and which method a certain route should take.