AngularJS/MVC Cookbook Running Unit Tests

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")" />
  http://@Url.Content(
  http://@Url.Content(

  <!-- include source files here... -->
  http://@Url.Content(
  http://@Url.Content(
  http://@Url.Content(
  http://@Url.Content(
  http://@Url.Content(
  http://@Url.Content(

  <!-- include spec files here... -->
  http://@Url.Content(
  http://@Url.Content(

  
    (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();
      }

    })();
  

</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.

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.

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-CookbookSimpleRoutingMvcAngular.Web” path:

testacular start Scriptstestingconfigtestacular-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.)

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.

Dave Baskin

Recent Posts

How to Navigate Azure Governance

 Cloud management is difficult to do manually, especially if you work with multiple cloud…

4 days ago

Why Azure’s Scalability is Your Key to Business Growth & Efficiency

Azure’s scalable infrastructure is often cited as one of the primary reasons why it's the…

3 weeks ago

Unlocking the Power of AI in your Software Development Life Cycle (SDLC)

https://www.youtube.com/watch?v=wDzCN0d8SeA Watch our "Unlocking the Power of AI in your Software Development Life Cycle (SDLC)"…

1 month ago

The Role of FinOps in Accelerating Business Innovation

FinOps is a strategic approach to managing cloud costs. It combines financial management best practices…

1 month ago

Azure Kubernetes Security Best Practices

Using Kubernetes with Azure combines the power of Kubernetes container orchestration and the cloud capabilities…

1 month ago

Mastering Compliance: The Definitive Guide to Managed Compliance Services

In the intricate landscape of modern business, compliance is both a cornerstone of operational integrity…

2 months ago