单元测试控制器中的angular.js服务(node.js服务器)

时间:2016-09-12 21:27:04

标签: angularjs node.js unit-testing mocha karma-mocha

我是客户端单元测试的新手。我的应用程序使用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)

1 个答案:

答案 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'));
...