我是客户端单元测试的新手。我的应用程序使用express.js,angularjs-ui-router和node.js.目前我开始为应用程序编写单元测试用例。我使用Karma,Mocha,Chai,Sinon进行单元测试。
我的路由器配置如下所示:
$stateProvider
.state('drive', {
url: '/drive',
templateUrl: 'drive.jade',
controller: 'driveCtrl',
});
控制器:
angular.module('mApp').controller('driveCtrl', ['$scope', 'driveService',
function($scope, driveService) {
var driveInfo = driveService.get({}, function() {});
driveInfo.$promise.then(function(rs) {
var drivers = [];
//Logical operation
$scope.drivers = drivers;
});
}]);
工厂资源:
mApp.factory('driveService', ['$resource', function($resource) {
return $resource('/drive/id/:id/', {id:'@id'});
}]);
driveService是一个工厂,内部使用angular.js $资源。我尝试了各种各样的选项但似乎没有用(使用$ httpbackend,$ q)。你能帮我写出通过模拟driveService来测试控制器的方法。
这是我的单元测试代码:
var expect = require('chai').expect;
var sinon = require('sinon');
describe('Drive Service initialisation', function() {
var scope, controller, state, $q, mockDriveService, driveServiceResponse = [{name:'james', type: 'heavy'}], queryDeferred;
beforeEach(angular.mock.module('mApp'));
angular.mock.module(function($provide){
$provide.value('driveService', mockDriveService);
});
describe(' drive service called', function() {
beforeEach(inject(function($controller, $rootScope, $state, _$q_, driveService) {
$q = _$q_;
scope = $rootScope.$new();
mockDriveService = {
get:function(){
queryDeferred = $q.defer();
queryDeferred.resolve(driveServiceResponse);
return {$promise: queryDeferred.promise};
}
};
controller = $controller('driveCtrl', { $scope: scope, driveService:driveService});
sinon.stub(mockDriveService, 'get');
scope.$apply();
}));
it('expect filter to be empty', function () {
expect(scope.drivers).to.not.be.empty;
});
});
});
我得到的错误是:
Error: Unexpected request: GET /driveService/id
No more request expected
at $httpBackend (node_modules/angular-mocks/angular-mocks.js:1210:9)
at sendReq (public/javascripts/lib/angular/angular.js:10333:9)
at serverRequest (public/javascripts/lib/angular/angular.js:10045:16)
at processQueue (public/javascripts/lib/angular/angular.js:14567:28)
at public/javascripts/lib/angular/angular.js:14583:27
at Scope.$eval (public/javascripts/lib/angular/angular.js:15846:28)
at Scope.$digest (public/javascripts/lib/angular/angular.js:15657:31)
at Scope.$apply (public/javascripts/lib/angular/angular.js:15951:24)
at Context.<anonymous> (C:/Users/por/AppData/Local/Temp/b0475694b46e0d60262621ad126ce46c.browserify:63:9)
at Object.invoke (public/javascripts/lib/angular/angular.js:4450:17)
Error: Declaration Location
at window.inject.angular.mock.inject (node_modules/angular-mocks/angular-mocks.js:2375:25)
答案 0 :(得分:0)
您正在定义一个模拟服务,但仍然为控制器提供了取消模拟的driveService
(默认情况下已经完成)。
在实例化控制器并调用该方法之后driveService.get
被存根的事实对此无效。
应该是
mockDriveService = {
get: sinon.stub().returns({$promise: $q.resolve(driveServiceResponse)})
};
controller = $controller('driveCtrl', { $scope: scope, driveService:mockDriveService});
scope.$apply();
该应用应该具有测试友好的设计,以便有效地进行测试。考虑到路由器在顶层模块中加载并且其配置也在那里定义,应该在子模块中定义应该测试的应用单元,因此可以单独测试它们。
该应用可能会被重构为
angular.module('mApp', ['ui.router', 'mApp.drive']);
...
angular.module('mApp.drive', [])
.controller('driveCtrl', ...)
.factory('driveService', ...);
其单位可能会像
一样进行测试beforeEach(angular.mock.module('mApp.drive'));
...