AngularJS/MVC Cookbook Running Unit Tests

No Comments February 18, 2013


Running Javascript unit tests is a little bit different than testing other code. In an NUnit test, for example, the system under test and the engine running the test share the same .NET runtime which allows for easy instantiation of the tests as well as collecting test results. In a Javascript test, however, the test is running within a Javascript engine which might be separate from the testing runner itself. Plus, the Javascript engine might be running within a real browser or in a “headless” browser configuration in a continuous integration (CI) environment.
Unit testing is of course only one type of testing you might perform. Another type of testing is integration or end-to-end testing.  But for now, let’s look at a few options for running Javascript unit tests – at least from a Windows/Visual Studio point of view.

Test Runner Web Page

One of the simplest ways to run Javascript unit tests is running the tests within the browser itself.  This means that a web application must serve up a test runner page that is responsible for actually executing the tests.
Jasmine provides a test runner page.  For the Simple Routing example, the test runner page looks like this:
@{
Layout = null;
}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Jasmine Spec Runner</title>

<link rel="stylesheet" type="text/css" href="@Url.Content("~/Scripts/testing/jasmine/jasmine.css")" />
<script type="text/javascript" src="@Url.Content("~/Scripts/testing/jasmine/jasmine.js")"></script>
<script type="text/javascript" src="@Url.Content("~/Scripts/testing/jasmine/jasmine-html.js")"></script>

<!-- include source files here... -->
<script type="text/javascript" src="@Url.Content("~/Scripts/angular/angular.js")"></script>
<script type="text/javascript" src="@Url.Content("~/Scripts/angular/angular-mocks.js")"></script>
<script type="text/javascript" src="@Url.Content("~/Scripts/app/home/homeModule.js")"></script>
<script type="text/javascript" src="@Url.Content("~/Scripts/app/home/homeCtrl.js")"></script>
<script type="text/javascript" src="@Url.Content("~/Scripts/app/home/contactCtrl.js")"></script>
<script type="text/javascript" src="@Url.Content("~/Scripts/app/home/aboutCtrl.js")"></script>

<!-- include spec files here... -->
<script type="text/javascript" src="@Url.Content("~/Scripts/testing/unit-tests/basicSpec.js")"></script>
<script type="text/javascript" src="@Url.Content("~/Scripts/testing/unit-tests/controllersSpec.js")"></script>

<script type="text/javascript">
(function() {
var jasmineEnv = jasmine.getEnv();
jasmineEnv.updateInterval = 1000;

var htmlReporter = new jasmine.HtmlReporter();

jasmineEnv.addReporter(htmlReporter);

jasmineEnv.specFilter = function(spec) {
return htmlReporter.specFilter(spec);
};

var currentWindowOnload = window.onload;

window.onload = function() {
if (currentWindowOnload) {
currentWindowOnload();
}
execJasmine();
};

function execJasmine() {
jasmineEnv.execute();
}

})();
</script>

</head>

<body>
</body>
</html>

Notice that the files for Jasmine, Angular (including mocks), the controllers (which are the system under test), and the test specifications are included.

Executing unit tests in this manner has the advantage that the tests can be run using whatever browser, or even whatever operating system, is of interest to you.



Chutzpah


If you are using Visual Studio 2012, the Chutzpah Test Adapter can be used to identify and run the Javascript unit tests. It integrates the test results in with results from other tests contained within the solution using the Test Explorer feature of Visual Studio 2012.

image

One of the things to remember about this method (and the Resharper method described next) is that you have to specify the dependencies of a test within the test script itself.  For example, for the controller tests the following lines are added to the top of the file to specify these dependencies:
/// <reference path="../../angular/angular.js" />
/// <reference path="../../angular/angular-mocks.js" />
/// <reference path="../../app/home/homeCtrl.js" />
/// <reference path="../../app/home/contactCtrl.js" />
/// <reference path="../../app/home/aboutCtrl.js" />



Resharper


If you are using Resharper, version 7 provides some additional unit testing features that allow you to run the Jasmine tests within Visual Studio.

image

Testacular


Testacular is a Javascript test runner and is the tool that is used by the AngularJS development team to create unit and end-to-end tests of the framework. It has the ability to monitor changes you make to code and provide immediate feed back of updated test results. You immediately know whether tests are now failing due to your code changes.

Testacular runs on top of NodeJS. To run the tests, a configuration file provides the information about where files are located, what browsers to use for running the tests, and how Testacular should operate.  In this project, the following configuration file is used:
basePath = '../../';

files = [
JASMINE,
JASMINE_ADAPTER,
'angular/angular.js',
'angular/angular-mocks.js',
'app/**/*.js',
'testing/unit-tests/**/*.js'
];

autoWatch = true;
logLevel = LOG_INFO; //LOG_DEBUG;
browsers = ['Chrome', 'IE'];
singleRun = true;

junitReporter = {
outputFile: 'test_out/unit.xml',
suite: 'unit'
};

To execute the tests, run the following command from the “Angular-MVC-Cookbook\SimpleRouting\MvcAngular.Web” path:
testacular start Scripts\testing\config\testacular-unit-tests.conf.js

So in theory, Testacular should report the status of the unit tests. However, for some reason, the tests were not being recognized for me. (I did try this in on a OSX system, and got the same results.)

image

So perhaps I’ve configured something wrong or there is a bug in the current AngularJS or Testacular code.  I’ll update this post if I find a fix.

Update 3/7/2013


I’ve checked in a change to the Testacular configuration that allows the tests to run now.  I had included “angular-scenario.js” which is used for end-to-end testing, not unit testing.  My mistake.  I’ve updated the configuration script above to reflect these changes.

No Comments

Have a Comment?