使用Node.js、Gulp.js和Mocha对angularjs控制器进行单元测试
我正在尝试使用Node.js对angularjs控制器进行单元测试。我正在使用gulp.js和mocha通过gulp mocha运行测试 这就是我的使用Node.js、Gulp.js和Mocha对angularjs控制器进行单元测试,angularjs,node.js,unit-testing,mocha.js,gulp,Angularjs,Node.js,Unit Testing,Mocha.js,Gulp,我正在尝试使用Node.js对angularjs控制器进行单元测试。我正在使用gulp.js和mocha通过gulp mocha运行测试 这就是我的gulpfile.js现在的样子: (function () { var gulp = require('gulp'); var mocha = require('gulp-mocha'); gulp.task('default', function () { return gulp
gulpfile.js
现在的样子:
(function () {
var gulp = require('gulp');
var mocha = require('gulp-mocha');
gulp.task('default', function () {
return gulp
.src('Scripts/Tests/*.js', { read: false })
.pipe(mocha({
ui: 'tdd',
reporter: 'dot',
globals: {
angular: require('./Scripts/angular.js')
}
}));
});
})();
这是正在测试的代码:
(function () {
var application = angular.module('Main');
application.controller('MainController', ['$scope', function ($scope) {
$scope.isDisabled = function () {
return true;
};
}]);
})();
这是测试文件本身:
(function () {
var chai = require('chai');
var assert = chai.assert;
angular.module('Main', []); // Create an empty module
require('../MainController.js'); // Fill the module with the controller
suite('Main Controller', function () {
test('isDisabled always true', function () {
var controllerFactory = angular.injector.get('$controller');
var controller = controllerFactory('MainController', {
'$scope': {}
});
var result = controller.isDisabled();
assert.isTrue(result);
});
});
})();
为了使我的测试和我正在测试的文件能够正常工作,我需要创建一个全局文件。但是,在gulpfile.js
中调用require
会给我一个参考错误:窗口未定义
错误。这是有道理的,因为我是在Node.js中运行的
在Node.js中加载angular需要做什么?我在Grunt中这样做,但同样的原则也适用于Gulp。您需要注入“angularmocks.js”文件,以便能够模拟依赖项注入。我正在使用Karma进行此操作,并在Karma.conf.js文件中进行设置,如下所示:
module.exports = function(config){
config.set({
basePath : '../../',
files : [
'bower_components/angular/angular.js',
'bower_components/angular-mocks/angular-mocks.js',
...
然后,您可以将$controller注入到测试中,并执行诸如测试控制器初始化之类的操作。下面的测试是初始化作用域,然后测试控制器是否正在向作用域添加方法(注意,我使用的是Jasmine,但mocha也可以这样做),但是Jasmine具有一些很好的内置间谍功能
describe('analysisController', function () {
var scope, state;
beforeEach(function () {
module('analysis');
scope = {
$apply:jasmine.createSpy(),
ws: {
registerCallback:jasmine.createSpy(),
sendMessage:jasmine.createSpy()
}
},
state = {
go : jasmine.createSpy()
};
});
it('should add a bunch of methods to the scope', inject(function ($controller) {
$controller('analysisController', {
$scope : scope,
$state: state
});
expect(typeof scope.colorContrast).toBe('function');
expect(typeof scope.XPathFromIssue).toBe('function');
}));
...
正如@unobf所说(以及angularjs文档所说),从Node.js测试angular的诀窍是使用Karma。这意味着安装karma
和karma mocha
,以及karma chrome launcher
、karma ie launcher
、karma firefox launcher
(或其他)通过npm安装
然后我基本上必须从头开始重做我的gulp.js
文件:
(function () {
var gulp = require('gulp');
var karma = require('karma').server;
gulp.task('runTests', function (done) {
karma.start({
configFile: __dirname + '/karma.config.js',
singleRun: true
}, done);
});
gulp.task('default', ['runTests']);
})();
我还必须创建一个karma.config.js
文件,将karma配置为使用Chrome、Firefox和mocha。在同一个文件中,我将mocha配置为使用tdd UI和dot reporter:
module.exports = function(config) {
config.set({
browsers: ['Chrome', 'Firefox', 'IE'],
frameworks: ['mocha'],
files: [
'./Scripts/angular.js',
'./Scripts/chai.js',
'./Scripts/*.js',
'./Scripts/Tests/*.js'
],
singleRun: true,
client: {
mocha: {
reporter: 'dot',
ui: 'tdd'
}
}
});
};
我了解到您必须首先指定angularjs、chai.js等,以便首先获取它们,然后在全局范围内获取其他文件。同样,测试代码的文件必须在测试文件之前列出
正在测试的代码根本没有改变。当我的测试运行时,我意识到我的测试被破坏了,结果看起来是这样的:
(function () {
var assert = chai.assert;
suite('Main Controller', function () {
test('isDisabled always true', function () {
var injector = angular.injector(['ng', 'Main']);
var $controller = injector.get('$controller');
var scope = {};
var controller = $controller('MainController', {
'$scope': scope
});
var result = scope.isDisabled();
assert.isTrue(result);
});
});
})();
最大的好处是控制器只需填充$scope
对象。我在$scope
对象上调用isDisabled()
。当然,获取控制器需要大量工作,因此使用angularmocks.js提供的inject
方法更有意义:
(function () {
var assert = chai.assert;
suite('Main Controller', function () {
var $scope = {};
setup(function () {
module('Main');
inject(function ($controller) {
$controller('MainController', {
'$scope': $scope
});
});
});
test('isDisabled always true', inject(function ($controller) {
var result = $scope.isDisabled();
assert.isTrue(result);
}));
});
})();
希望这足以让任何试图使用Node.js和mocha测试angularjs代码的人开始学习。你能告诉我全局inject
是从哪里来的吗?有没有其他方法来获取$controller
?我最终只是通过angular.injector(['ng','Main']).get('$controller')
创建了一个注入器。尽管如此,我还是会在我的真实项目中使用angular mock。谢谢你的详细解释。