8

Lets say i have an angular module defined as

var app = angular.module('app',[dependenceny1Module,dependenceny2Module,dependenceny3Module......])

where app is a module which depends on bulk of other modules. Now for unit testing i can mock the module using

mock('app') 

but i have to create mock modules for all dependency modules like below

mockDependency1 = angular.module('dependency1Module')
mockDependency1 = angular.module('dependency2Module')

Or i have to load all the script files containing those modules.

I am wondering whats the best approach to mock out the dependency modules here? especially when dependency modules are too many.

2
  • What's the problem with loading the other modules during testing? Honest question, maybe your environment causes issues? Also what other tools are you using for testing? Karma? Grunt? Jasmine? Commented Feb 25, 2014 at 20:41
  • Are you testing during a "build"? Are you testing on your web page itself? A hosted spec file? Commented Feb 25, 2014 at 20:42

3 Answers 3

8
+50

Look into requireJs to load your dependencies. With RequireJs, you can load different files for your production code and your test code.

Here is a (basic) example.

Let's say you have a javascript file with defines your angular module (named e.g app.js):

define(['dependency1Module', 'dependency2Module'], function(dependency1Module, dependency2Module) {
   var app = angular.module('app',['dependenceny1Module', 'dependenceny2Module']);
   return app;
}

Modules dependency1Module, dependency2Module, ... have a similar setup:

define(function() {
   var module = angular.module('dependenceny1Module');
   return module;
}

Now you need a bootstrap file (named e.g. bootstrap.js to define the location of the files. So you'll have two bootstrap files: one your your production code (using possible minified versions of some libraries) and a version for test purposes:

require.config({
  baseUrl: "path/to/production|test scripts",
  paths: {
    angular: 'path/to/angular',
    jquery: 'path/to/jquery',
  },
  shim: {
    angular: {
      exports: 'angular',
      deps: ['jquery']
    }
  }
});

require(["angular", "app", ], function(angular, app) {
  angular.element(document).ready(function() {
    angular.bootstrap(document, ['app']);
  });
});

Instead of changing the baseUrl, you could define different paths for the modules you want to mock:

paths: {
   dependency1Module: 'path/to.mock/dependency1Module'
}

Last step is to plugin the bootstrap file in your html code (production or test):

<script type="text/javascript" src="path/to/require.js"></script>
<script type="text/javascript" src="path/to/bootstrap(production|test).js"></script>

This is a basic requirejs setup. Of course, before you can use a certain angular type (e.g. controller, service, ...), you'll need to setup a requirejs module for it too (and requireit e.g in your app.js).

Sign up to request clarification or add additional context in comments.

2 Comments

I like this answer just because of RequireJS... however, I'm not sure what issue the OP is trying to solve still. Why can't he reference the other files? Maybe he can't reference requirejs either? Where are the tests running? etc.
If your production needs dependency1Module.js but you want to use mock-Dependency1Module.js in all your tests, then you can just include mock-Dependency1Module.js that file in your karma.config.js instead of the real file. I think adding RequireJs to a project for the sake of testing/mocking might be a bit overkill.
1

Modularizing your own app will help.

If your app looks like this:

var app = angular.module('app',[dependenceny1Module, dependenceny2Module, dependenceny3Module......])

and contains 50 things like filters, directives and controllers. Some of them depend on dependenceny1Module and some of them depend on dependenceny2Module.

Break them apart based on their responsibilities and dependencies.

var mymodule1 = angular.module('mymodule1',[dependenceny2Module, dependenceny3Module])

var mymodule2 = angular.module('mymodule2',[dependenceny1Module,])

Then make your app depend on your own modules:

var app = angular.module('app',[ mymodule1, mymodule2])

Your app should have mostly bootstrap code.

Now when you want to test controller13 of mymodule2, you will only have to mock mymodule2's dependencies if that module has dependencies. So test suites will not load app they will only load the module they test.

See this example where the tests for MyMainCtrl1 of mymodule1 only care about s1 from external1 even if the app as a whole depends on external1, external2 and external3.

Comments

0

It all depends on what you actually want to test, if you are unit testing you want load/mock as little as possible. For example, if you unit test a controller, you mock the module and only load/mock whatever dependencies it uses.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.