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.

Tuesday, 6 September 2011

Additional methods in the unit testing of Javascript

More methods to the unit testing of javascript
I am building upon the great example of unit testing in javascript by Stephen Walther, and will now present additional methods to the JavascriptUnitTestingFramework.js file he presented.

Let me first list up the new contents:



var assert = {

areEqual: function (expected, actual, message) {
if (expected !== actual) {
throw new Error("Expected value " + expected
+ " is not equal to " + actual + ". " + message);
}
},

areNotEqual: function (expected, actual, message) {
if (expected === actual) {
throw new Error("Expected value " + expected
+ " is equal to " + actual + ". " + message);
}
},

isTrue: function (actual, message) {
if (!actual) {
throw new Error("The provided actual value" + actual + " is not evaluating to true. " + message);
}
},

isNull: function (actual, message) {
if (actual != null) {
throw new Error("The provided actual value " + actual + " must be null. " + message);
}
},

isNotNull: function (actual, message) {
if (actual == null) {
throw new Error("The provided actual value " + actual + "must be not null." + message);
}
},

isFalse: function (actual, message) {
if (actual) {
throw new Error("The provided actual value " + actual + " must be false. " + message);
}
},

isInstanceOfType: function (actual, type, message) {
if ((actual instanceof type) == false) {
throw new Error("The provided actual value " + actual + " is not an instance of type " + type + ". " + message);
}
},

referenceEquals: function (actual, expected, message) {
if (actual !== expected) {
throw new Error("The provided actual and expected values does not point to the same object. Actual is " + actual + " and expected is " + expected + " " + message);
}
}

};



I have added much of the methods of the Assert class in C#. The Assert class have static methods such as ReferenceEquals, IsTrue, IsFalse, AreNotEqual and so on and these methods have now been added above.


Lets continue with the javascript unit tests using this js file.



//At the start of the file for your javascript unit tests
//add a reference to the unit testing reference file JavascriptUnitTestingFramework.js
//Use the reference element and three slashes.

function testAddNumbers() {
// Act
var result = addNumbers(1, 3);

// Assert
assert.areEqual(4, result, "addNumbers did not return right value!");
}

function testFactorial() {
var result = factorial(5);
assert.areEqual(120, result, "factorial did not return righ value!");
}

function testIsTrue() {
assert.isTrue(110 > 0, "This must evaluate to true for the test to pass.");
}

function testIsNull() {
var city = null;
assert.isNull(city, "Must be null");
}

function testIsNotNull() {
var city = { name: "London" };
assert.isNotNull(city, "Must be not null");
}

function testIsFalse() {
var actual = 4 > 5;
assert.isFalse(actual, "The expression must evaluate to false.");

}

function testIsInstanceOfType() {
assert.isInstanceOfType(new String("mystring"), String, "The provided actual value must be an instance of type String.");
assert.isInstanceOfType([1, 2, 3, 4], Array, "The provided value must be an
instance of an array.");
}

function testAreNotEqual() {
assert.areNotEqual("abc", "abbc", "Provided expected value and actual value are not equal");
}

function testAreEqual() {
assert.areEqual("def", "def", "The two provided values does not agree.");
}

function testReferenceEquals() {
var a = { city: "Manchester" };
// var c = { country: "Ireland" };
var b = a;
assert.referenceEquals(a, b, "The two objects does not point to the same object.");
}



The unit tests written in C# then looks like this:



[TestMethod]
public void TestFactorial()
{
var jsHelper = new JavaScriptTestHelper(this.TestContext);

jsHelper.LoadFile("JavaScriptUnitTestFramework.js");
jsHelper.LoadFile(@"..\..\..\MvcApplication1\Scripts\Math.js");
jsHelper.LoadFile("MathTest.js");

jsHelper.ExecuteTest("testFactorial");

}

[TestMethod]
public void TestIsTrue()
{
var jsHelper = new JavaScriptTestHelper(this.TestContext);

jsHelper.LoadFile("JavaScriptUnitTestFramework.js");
jsHelper.LoadFile(@"..\..\..\MvcApplication1\Scripts\Math.js");
jsHelper.LoadFile("MathTest.js");
jsHelper.ExecuteTest("testIsTrue");
}

[TestMethod]
public void TestIsNull()
{
var jsHelper = new JavaScriptTestHelper(this.TestContext);
jsHelper.LoadFile("JavaScriptUnitTestFramework.js");
jsHelper.LoadFile(@"..\..\..\MvcApplication1\Scripts\Math.js");
jsHelper.LoadFile("MathTest.js");
jsHelper.ExecuteTest("testIsNull");
}


[TestMethod]
public void TestIsNotNull()
{
var jsHelper = new JavaScriptTestHelper(this.TestContext);
jsHelper.LoadFile("JavaScriptUnitTestFramework.js");
jsHelper.LoadFile(@"..\..\..\MvcApplication1\Scripts\Math.js");
jsHelper.LoadFile("MathTest.js");
jsHelper.ExecuteTest("testIsNotNull");
}

[TestMethod]
public void TestAreEqual()
{
var jsHelper = new JavaScriptTestHelper(this.TestContext);

jsHelper.LoadFile("JavaScriptUnitTestFramework.js");
jsHelper.LoadFile(@"..\..\..\MvcApplication1\Scripts\Math.js");
jsHelper.LoadFile("MathTest.js");
jsHelper.ExecuteTest("testAreEqual");
}

[TestMethod]
public void TestIsFalse()
{
var jsHelper = new JavaScriptTestHelper(this.TestContext);

jsHelper.LoadFile("JavaScriptUnitTestFramework.js");
jsHelper.LoadFile(@"..\..\..\MvcApplication1\Scripts\Math.js");
jsHelper.LoadFile("MathTest.js");
jsHelper.ExecuteTest("testIsFalse");
}

[TestMethod]
public void TestIsInstanceOfType()
{
var jsHelper = new JavaScriptTestHelper(this.TestContext);
jsHelper.LoadFile("JavaScriptUnitTestFramework.js");
jsHelper.LoadFile(@"..\..\..\MvcApplication1\Scripts\Math.js");
jsHelper.LoadFile("MathTest.js");
jsHelper.ExecuteTest("testIsInstanceOfType");
}

[TestMethod]
public void TestAreNotEqual()
{
var jsHelper = new JavaScriptTestHelper(this.TestContext);
jsHelper.LoadFile("JavaScriptUnitTestFramework.js");
jsHelper.LoadFile(@"..\..\..\MvcApplication1\Scripts\Math.js");
jsHelper.LoadFile("MathTest.js");
jsHelper.ExecuteTest("testAreNotEqual");

}

[TestMethod]
public void TestReferenceEquals()
{
var jsHelper = new JavaScriptTestHelper(this.TestContext);
jsHelper.LoadFile("JavaScriptUnitTestFramework.js");
jsHelper.LoadFile(@"..\..\..\MvcApplication1\Scripts\Math.js");
jsHelper.LoadFile("MathTest.js");
jsHelper.ExecuteTest("testReferenceEquals");

}



Ok, so as the methods above show that much of the action should take place in the TestInitialize method. I will leave that to figure out for yourself, basically the methods will have some similar Arrange for the individual unit tests.

So what we now have is a basic way of performing unit tests against javascript using MSTest with methods such as AreNotEqual, AreEqual, IsNull, IsNotNull, ReferenceEquals, IsTrue, IsFalse that are available when doing ordinary C# unit tests.

Using Stephen Walter's solution makes the client code developer focus at the task at hand at writing Javascript code and companion unit test. I would not suggest that you unit test the jQuery based javascript "Gui code", since you need to have a document loaded (with companion DOM tree). Instead, what you should unit test of your javascript code would be your custom logic which is kind of independent of the "GUI" and as such is suitable to doing unit tests and TDD. I find myself now using these unit tests as a quick way of performing TDD with javascript. When developing the factorial function for example, I could verify that the code I was writing by remembering my university days of how a factorial function was indeed spot on by executing a unit test. These unit tests are alsovery convenient to modify and executes very quickly, outside any browser and web server.

I will now include a zipped file that contains a Visual Studio 2010 solution with a test project that shows how the unit tests are for javascript code is running under MSTest. You will need Microsoft Visual Studio 2010 with support for test projects to open up the solution, this is not supported in Visual Studio 2010 Express.. Many thanks to Stephen Walther for making the unit testing in javascript possible!

Download the zipped solution with the javscript unit testing framework and companion unit tests in C¤ / javscript here right here from 2Shared drop location:

Download zipped solution here of this article [zip]

Unit testing in Javascript done the right way!

Monday, 5 September 2011

Unit testing of javascript in MVC 3 application

Goal: Unit testing the javascript code
In todays modern web applications, unit testing all your layers should be a goal. Often a developer unit tests the C#-code, so why only write unit tests for the server code, when the client code (such as javascript) is just as important? The end user uses both, and if there are custom logic in your javascript the code should definately have its own unit tests. In this article I will explain my own little adventure into looking at the possibilities I have to unit test my javascript code.

Initial spin
I have trying to resolve the issue of how to proper unit test javascript code in a MVC application the latest days. Basically I initially started out with the idea of definining which javascript code I would like to load and which unit test I would like to run. I ended up creating a test solution which was essentially working, but I did not like the end result. The good part was that I was using the QUnit unit testing framework that much of jQuery is based upon. I basically wrote the necessary code to define the javascript and the unit tests to run and I then looped through the list to launch off the browser to display results from QUnit. Yes, this works and yes it uses the elegant QUnit framework - but there are several negative sides of this browser launcher approach. The really negative part is that these browser launched tests needs non-automatic supervision. The tester must inspect the results in the browser and there is really a lot of dependendency going on. We need a working browser and web server, so this is not a general unit test. I was striving to find the solution, and in general I wanted to use MS Test, i.e. I wanted to define ordinary unit tests that were "javascript flavored". Before venturing too deep into this seemingly mess, I discovered that somebody else already had thought of this.

Stephen Walter to the rescue
In his blog article, Stephen Walter explains how to do the proper unit test
with MsTest, which is just what I wanted. Best of all, since we now can use MsTest this will support automatic running of unit tests and fits nicely into MSBuild and the rest of the test infrastructure. Finally the javascript code can be put under control! What I then did was read through Stephen Walter's article and test out his complementary solution. It worked perfectly out of the box, and I do not see much changes that needs to be done to make this suit perfect into MVC 3 as Stephen Walter already shows the solution in such an application.

Summing up the article of Steven Walter
I just want to confirm to the rest of the interested party that Steven Walter's solution to unit tests in javascript is working perfectly. I will present his solution in summary form next. First of all, the unit test project added to the MVC
project that should have tests for javascript must have a reference to the Microsoft Script Control. This is an ActiveX COM component. The addon can be downloaded using the link next: Microsoft Script Control 1.0. Once this DLL has been added to the unit test project, you want to add a unit test. This will not be a basic unit test, as this kind of test does not have a TestContext, which will be needed. Second, add a folder called helpers, and add Stephen Walter's helper class for running the javascript code. The javascript code and javascript unit test will not run in a browser envrironment, but use the ScriptControl class. This will behind the scenes actually use the JScript engine which means that the browser in effect we test is Internet Explorer 8. This will actually suit our needs, since the loading of the additional libraries such as jQuery to support cross browser support should also be needed. The plumbing code to set up the ScriptControl with the correct .js library files I would suggest is set up in the TestInitialize method of your unit test, and it should call a common method, preferably also in Helpers folder to load up the "default" jquery javascript files once javascript code that uses jQueryis to be tested. Beware of the ordering of loading the js files. The js files should be as default be built using build type content (we will load up these files using "loose files"). The path pointing to the js files should point to the javascript files in the Content/Scripts folder. In general, javascript that should be tested and be available for the views should in general reside in the Content/Scripts folder for a MVC application. The tests written in javascript is in Steven Walters example put in a folder called JavascriptTests in the test project. This looks like a good practice. In general, the folder structure under Content/Scripts should somehow match the folder structure under JavascriptTests, once one gets more javascript tests added.

In Steven Walther's article there is a specific step of setting up the test settings for the javascript code to deploy a folder for the javascript code during the execution of the test. This step should be carefully read, since the tests needs to find the javascript files during the testexecution. Basically, a .testsetting file needs to be added to the solution to make this possible, so I just refer to the article.

Let me present the helper class which Steven Walter created for instantiating and initializing the ScriptControl instance.



public class JavaScriptTestHelper : IDisposable {

private ScriptControl _sc;
private TestContext _context;

///
/// You need to use this helper with Unit Tests and not
/// Basic Unit Tests because you need a Test Context
///

/// Unit Test Test Context
public JavaScriptTestHelper(TestContext testContext) {
if (testContext == null) {
throw new ArgumentNullException("TestContext");
}
_context = testContext;

_sc = new ScriptControl();
_sc.Language = "JScript";
_sc.AllowUI = false;
}

///
/// Load the contents of a JavaScript file into the
/// Script Engine.
///

/// Path to JavaScript file
public void LoadFile(string path) {
var fileContents = File.ReadAllText(path);
_sc.AddCode(fileContents);
}

///
/// Pass the path of the test that you want to execute.
///

/// JavaScript function name
public void ExecuteTest(string testMethodName) {
dynamic result = null;
try {
result = _sc.Run(testMethodName, new object[] { });
} catch {
var error = ((IScriptControl)_sc).Error;
if (error != null) {
var description = error.Description;
var line = error.Line;
var column = error.Column;
var text = error.Text;
var source = error.Source;
if (_context != null) {
var details = String.Format("{0} \r\nLine: {1} Column: {2}", source, line, column);
_context.WriteLine(details);
}
}
throw new AssertFailedException(error.Description);
}
}

public void Dispose() {
_sc = null;
}



The JavascriptTestHelper class of Steven Walter basically news up a ScriptControl class and contains two methods to load a javscript file (.js) and then exceute the test. Of course, several javascript files can be added. Note that the ScriptControl instance which is a COM object needs to be nulled when disposing the object.

Ok, so this is the class that will be used when writing the [TestMethod] in C# for the javascript test. Basically we must arrange the test using this testhelper to load up the .js files, and then use the test helper to execute the javascript test. The test method name must be added also to the ScriptController instance before starting up.

Every javascript unit test will of course in essence be written in Javascript, the C# based unit test is just a wrapper, the really interesting part is as always in Javscript when it comes to the client code. So each javascript class will then refer to a utility library. Steven Walther gives a very simple example of such a library, which is nothing more than providing a AreEqual function. The unit test written in javascript will then refer to this "library", using the ///
syntax. This library will be in the base path of he JavascriptTests folder for now. The path must point to this JavascriptUnitTestLibrary.js file. The AreEqual method is really simple and the addition of more methods to support different errors should be a overcoming task. I will myself try out addind more such methods. The sad part is that this code does not use QUnit to support more function that Steven Walter's AreEqual metod, but this method covers very much of the needed functionality. I will soon add more examples of unit testing functions soon into this file.

Here is the JavascriptUnitTestLibrary.js file:

var assert = {

areEqual: function (expected, actual, message) {
if (expected !== actual) {
throw new Error("Expected value " + expected
+ " is not equal to " + actual + ". " + message);
}
}

};

The little library does nothing more than define an object with a single method areEqual which will throw an error. The script controller will in the helper class
catch this error and then rethrow it into an AssertFailedException, which MSTest will then recognize and we are getting our fancy detection of errors in Javascript that MSTest will see! Elegant!

So the only thing next when it comes to the javascript unit test is to write the test and use this utility library. Lets add a new test for demonstrational purposes to the addTwoNumbers method Steven Walther was presenting in this article, the factorial of a number, let's put this additional code to MathTest.js (the reference line at the top should only be listed once).

MathTest.js:

///
function testFactorial() {
var result = factorial(5);
assert.areEqual(120, result, "factorial did not return righ value!");
}

This test will then assert that the factorial of five is equal to 120 (check with your calculator!). The MathTest.js file is added to the JavascriptTests folder.

Ok, so next up is then writing the unit test, add a new unit test to the test project
and then write the following:

[TestMethod]
public void TestFactorial()
{
var jsHelper = new JavaScriptTestHelper(this.TestContext);
jsHelper.LoadFile("JavaScriptUnitTestFramework.js");
jsHelper.LoadFile(@"..\..\..\MvcApplication1\Scripts\Math.js");
jsHelper.LoadFile("MathTest.js");
jsHelper.ExecuteTest("testFactorial");
}

If you can't understand why the code in the JavascriptTests are references as seemingly being in the same folder as the unit test (which is one folder up), this is handled by the testsettings file added previously. Refer to Steven Walthers article.

The test method in my file, UnitTest1.cs is then newing up the test helper class
and make note, passes in the testcontext of my unit test, which is why a basic unit
test will not suffice in this case. Then the ordering of loading the js files is
important. First the unit test framework js file is added. Then the javascript
code is added which will be tested. Next up the javascript code that contains the
javascript based test is added. If your javascript code uses a lot of jQuery libraries, additional js files should be added before the user provided javascript
code. The ordering is as previously mentioned important, and the paths should be correct. Basically one wants to go up three levels of the current directory and then go into the Scripts or Content/Scripts folder to the target .js file. I really suggest that the Scripts folder should be the place that custom javascript is added and that the .js files that the user creates should be in sub folders here. The base directory of the Scripts folder should only contain the jquery libraries and similar, not the user based code, as this is not very scalable as the web project grows..

Finally the ExecuteTest is called and the parameter provided is the name of the javascript test.

I also of course had to add the factorial function in the Math.js. This code looks like this:


function factorial(n) {
if (n > 1) {
return n * factorial(n - 1);
}
else {
return 1;
}
}

This factorial function uses recursion to return the factorial of a number. The code is almost the same as a C# based function for the factorial.

Then I just ran the unit test with Ctrl+R and Ctrl+T and saw it pass in the test results. Great stuff Steven Walther! I believe this is the correct way to do unit tests in javascript, i.e. not using QUnit.

The next obvious task is to implement more code to Steven Walther's JavascriptUnitTestLibrary.js file. This should be a near future task I will look into.

I have looked at other parts of unit testing MVC applications. Unit testing controllers are actually very good supported, as these are ordinary classes, which requests can be mocked. The unit testing of views is possible using the RazorSingleFileGenerator or RazorGenerator extension (although many means that unit testing a MVC view should be avoided).

One open issue is how to unit test a MVC 3 Razor helper, I will look into this perhaps using RazorSingleFileGenerator extension in the near future..