Adding unit tests to an existing application can be a challenge. If the application wasn’t developed with testing in mind, getting your source code into shape so that your components are isolated and testable is like adding a new character to a story after the book is already written. Significant refactoring must be done to decouple and test your code.

A particular challenge in writing unit testable code is mocking the dependencies in your test subjects. You need some means of exposing the “handles” of dependencies so that a test can pull them out and replace them with controllable mocks. If you don’t replace these dependencies, you can’t write a true unit test, since breakage in a dependency would result in a failing test. This breaks the contract of a unit test. If the subject being tested works correctly, the test should pass, even if a service or utility the subject depends on is faulty. Failures in the service or utility the test subject depends on should be caught by a separate unit test written for that service or utility.

At The New York Times, the CMS team has been writing unit tests for a new article editing application we developed for Scoop. Because we built it with Backbone.js and because it is AMD-compliant (each Backbone component or shared service, vendor library or utility class is a RequireJS module), the app was pretty modular even before we considered unit testing.

However, even though RequireJS provides numerous benefits in terms of dependency resolution and modularity, it doesn’t provide a means of doing dependency injection. When RequireJS sees that one module depends on another, it resolves the dependency module against a path in a configuration file before the dependent module is defined. This binds each dependency to an implementation and precludes dependency injection.

Consider this example of a Backbone (Brace) Lock model, a RequireJS module that depends on the UserService module:

// Lock.js define ( function ( require ) { var UserService = require ( "services/userService.js" ) ; return Brace. Model . extend ( { namedAttributes : { user : Object , name : String , lockedByCurrentUser : Boolean , // more attributes ... } , initialize : function ( options ) { this . lockedByCurrentUser = UserService. getCurrentUser ( ) . get ( "userId" ) === this . get ( "user" ) . userId ; } , // ... } ) ; } ) ;

UserService is declared outside of the body of the Lock and is defined (by RequireJS) before Lock’s definition is evaluated. Lock is then a closure around UserService, and all references to UserService are internal to Lock. This encapsulation is good because clients of the Lock shouldn’t use the UserService through the Lock, but it creates a problem when the client of the Lock is a unit test. The UserService has no handle by which a unit test could mock it out.

In order to expose UserService, we would have to refactor the Lock. For example, we could set the UserService as a property on the Lock (e.g., myLock._userService ) so that we could override it in a test:

// Lock.js define ( function ( require ) { var UserService = require ( "services/userService.js" ) ; return Brace. Model . extend ( { namedAttributes : { user : Object , name : String , lockedByCurrentUser : Boolean , } , _userService : UserService , initialize : function ( options ) { this . lockedByCurrentUser = this ._userService. getCurrentUser ( ) . get ( "userId" ) === this . get ( "user" ) . userId ; } , // ... } ) ; } ) ; // LockSpec.js define ( function ( require ) { var Lock = require ( "components/locking/Lock.js" ) ; describe ( "A Lock" , function ( ) { it ( "is locked by the current user if the current user is the Lock's user" , function ( ) { var currentUser = new Backbone. Model ( { name : "Ben Wilhelm" } ) ; var lock = new Lock ( { name : "headline" , user : currentUser } ) ; // create a mock _userService and set it on the Lock lock._userService = { getCurrentUser : function ( ) { return currentUser ; } } ; lock. initialize ( ) ; // Lock is reinitialized, this time with the mock expect ( lock. lockedByCurrentUser ) . toBe ( true ) ; } ) ; } ) ; } ) ;

This is bad because it requires us to reinitialize the Lock model in our test in order to use the mock UserService, which could result in unexpected side effects if initialize() isn’t idempotent. initialize() would have been called the first time when the Lock was constructed.

To get around double initialization, we could inject the UserService when a Lock is instantiated by passing the UserService as an option to initialize() and then setting the _userService property there. The test could then simply instantiate a Lock with a mock UserService:

// Lock.js define ( function ( require ) { // remove UserService as a dependency and let each client provide a UserService // implementation to the Lock return Brace. Model . extend ( { namedAttributes : { user : Object , name : String , lockedByCurrentUser : Boolean } , _userService : { } , initialize : function ( options ) { // Let each client pass in the UserService as a constructor option this ._userService = options. userService ; this . lockedByCurrentUser = this ._userService. getCurrentUser ( ) . get ( "userId" ) === this . get ( "user" ) . userId ; } , // ... } ) ; } ) ; // LockSpec.js define ( function ( require ) { var Lock = require ( "components/locking/Lock.js" ) ; describe ( "A Lock" , function ( ) { it ( "is locked by the current user if the current user is also the Lock's user" , function ( ) { var currentUser = new Backbone. Model ( { name : "Ben Wilhelm" } ) ; var mockUserService = { getCurrentUser : function ( ) { return currentUser ; } } ; var lock = new Lock ( { name : "headline" , user : currentUser } , { userService : mockUserService } ) ; expect ( lock. lockedByCurrentUser ) . toBe ( true ) ; } ) ; } ) ; } ) ;

This is safer and cleaner, but it just passes the buck by causing all Lock clients to depend on UserService, only to pass UserServices back to the Lock. It also breaks our encapsulation of UserService by exposing the _userService property on the Lock. Furthermore, because so many of our components’ dependencies are already declared the way they are, it would require us to refactor almost every component in our source code.

Ideally, we could keep the UserService definition where it is, but have the ability to control how it is defined when loaded by RequireJS. That way, we could write a mock UserService module in our unit test and have the Lock require() the mock instead of the real thing.

Enter Squire.js

Because RequireJS is not a dependency injection framework, there are no methods in the API that are intended for swapping out modules during runtime. However, the contexts are exposed in a property (requirejs.s.contexts), and monkey patching this property could get us what we wanted. This is exactly what the open source library, Squire, does. Squire is easy to install, easy to use, requires no configuration and does just what we need.

How to Use Squire

Squire can be installed in your project as a bower dependency or as an npm module. How you get it into your tests depends on what test runner you’re using (we use Grunt and Jasmine), but you can load it into your test just like any other module, assuming you’ve configured Squire as a dependency module in your runner’s RequireJS config. Then, you can instantiate a Squire injector and register any mock modules that will be depended on by the subject under test. When you use the injector’s require() method to require the subject, any mock modules you gave to Squire will be injected when the subject requires them.

// in Gruntfile.js jasmine : { run : { src : [ "src/app.js" ] , // this file requires all of our vendor libs options : { specs : [ "tests/unit/**/*Spec.js" ] , host : "//127.0.0.1:8005/" , template : require ( "grunt-template-jasmine-requirejs" ) , templateOptions : { requireConfig : { baseUrl : "src/" , paths : { squire : "vendors/squire/src/Squire" , sinon : "vendors/sinonjs/lib/sinon" , // other test dependencies… } } , keepRunner : true // other RequireJS config options… } } } } // Lock.js define ( function ( require ) { // The "services/userService.coffee" module will be mocked in our test, but // not in the app, so our source stays the same. var UserService = require ( "services/userService.js" ) ; // No need for a _userService property. UserService remains encapsulated return Backbone. Model . extend ( { namedAttributes : { user : Object , name : String , lockedByCurrentUser : Boolean } , initialize : function ( options ) { this . lockedByCurrentUser = UserService. getCurrentUser ( ) . get ( "userId" ) === this . get ( "user" ) . userId ; } // ... } ) ; } ) ; // LockSpec.js define ( function ( require ) { var Squire = require ( "squire" ) ; describe ( "A Lock" , function ( ) { var injector ; // the Squire.js instance (for mock RequireJS module injection) var currentUser ; beforeEach ( function ( done ) { injector = new Squire ( ) ; } ) ; it ( "is locked by the current user if the current user is also the Lock's user" , function ( done ) { var mockUserService = { getCurrentUser : function ( ) { return currentUser ; } } ; injector. mock ( "services/userService.js" , mockUserService ) ; // Since we've mocked userService, anything that requires it, such as // Lock (below), will get the mockUserService instead of the real one injector. require ( [ "components/locking/Lock.js" ] , function ( Lock ) { currentUser = new Backbone. Model ( { name : "Ben Wilhelm" } ) ; // No need to reinitialize the Lock after instantiation var lock = new Lock ( { name : "headline" , user : currentUser } ) ; expect ( lock. lockedByCurrentUser ) . toBe ( true ) ; done ( ) ; // end asynchronous execution } ) ; } ) ; } ) ; } ) ;

Because we’ve registered services/userService.js as a mock, components/locking/Lock.js will be injected with the mock UserService inside the callback passed as the second argument to injector.require().

Note that the callback passed to require() is executed asynchronously (just like RequireJS’s require() method), so tests requiring mocks will have to be run as asynchronous tests. Popular JavaScript testing frameworks provide methods for indicating to a test runner when asynchronous execution has ended and it should move on to the next test. Jasmine and Mocha, for example, provide a done() callback which can be passed into a test method and invoked at the end of an asynchronous operation like a require() callback.

Squire mocks can be stored on the injector instance and then be manipulated inside the injector’s require callback. By requiring the “mocks” module provided by Squire, which holds a map of all of your mocks (with module IDs for keys) in mocks.store, you can dynamically change the behavior of your mocks in each test:

// LockSpec.js describe ( "A Lock" , function ( ) { var injector , user , anotherUser ; beforeEach ( function ( done ) { var mockUserService = { // This implementation will be overridden in tests getCurrentUser : function ( ) { } } ; user = new Backbone. Model ( { name : "Ben Wilhelm" } ) ; anotherUser = new Backbone. Model ( { name : "Another User" } ) ; injector = new Squire ( ) ; injector. mock ( "services/userService.js" , mockUserService ) ; // Tell Squire to store our mocked 'services/userService.js' RequireJS module, // so that we have access to it in our tests injector. store ( "services/userService.js" ) ; } ) ; it ( "is locked by the current user if the current user is also the Lock's user" , function ( done ) { // Requiring the "mocks" module gives us access to our mock modules injector. require ( [ "mocks" , "components/locking/Lock.js" ] , function ( mocks , Lock ) { // Override the implementation of getCurrentUser on our mock UserService mocks. store [ "services/userService.js" ] . getCurrentUser = function ( ) { return user ; } ; var lock = new Lock ( { name : "headline" , user : user } ) ; expect ( lock. lockedByCurrentUser ) . toBe ( true ) ; done ( ) ; } ) ; } ) ; it ( "is not locked by the current user if the current user is not the Lock's user" , function ( done ) { injector. require ( [ "mocks" , "components/locking/Lock.js" ] , function ( mocks , Lock ) { // A new implementation of getCurrentUser() on the same mock mocks. store [ "services/userService.js" ] . getCurrentUser = function ( ) { return anotherUser ; } ; var lock = new Lock ( { name : "headline" , user : user } ) ; expect ( lock. lockedByCurrentUser ) . toBe ( false ) ; done ( ) ; } ) ; } ) ; } ) ;

Squire also offers a couple of nice helpers that can speed up the creation of mocks when you know what you want the module to return (or when the module returns a constructor function, and you know what you want the constructor function to return).

var mockInstance = require ( "tests/mocks/complexMockInstance" ) ; // Squire.Helpers.returns() creates a mock that returns the mockInstance itself injector. mock ( "services/userService.js" , Squire. Helpers . returns ( mockInstance ) ) ; // Squire.Helpers.constructs() creates a mock that returns a constructor function that // can be used to instantiate mockInstances injector. mock ( "services/userService.js" , Squire. Helpers . constructs ( mockInstance ) ) injector. require ( [ "services/userService.js" ] , function ( UserService ) { mockUserService = new UserService ( ) ; // Write tests... } ) ;

As you can see, Squire provides an easy-to-use, compact API for mocking RequireJS modules. Since all of our application components are RequireJS modules, Squire allowed us to make all of our dependencies injectable at once, without making any changes to our source code. This spared us a considerable amount of refactoring in order to make our application testable.