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.

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!