【问题标题】:Unit testing angular.js service (node.js server) in controller在控制器中单元测试 angular.js 服务(node.js 服务器)
【发布时间】:2023-03-30 05:26:01
【问题描述】:

我是客户端单元测试的新手。我的应用程序使用 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 $resources 的工厂。我尝试了多种选择,但似乎没有任何效果(使用 $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)

【问题讨论】:

  • 你到底尝试了什么?请指定您当前的规格。要求从头开始编写它们并不是一个真正的问题。
  • 我不希望有人写作。无论如何,我可以发布我写的内容。
  • 请发布它们,它们与问题相关。
  • @estus:给你。我试图解决这个错误,但没有成功。

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


【解决方案1】:

您正在定义一个模拟服务,但仍为控制器提供未模拟的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'));
...

【讨论】:

  • 在我的代码中应用更改后,得到相同的错误但请求其他 JADE 模板(这就是错误显示的内容)。这意味着请求将转到不同的模板。我还需要检查什么吗?这是错误Error: Unexpected request: GET partials/customer.jade 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 process
  • 真正的请求不能也不应该在单元测试中执行,这就是你得到这个错误的原因。触发http请求的是路由器。根本不应该在单元测试中加载路由器模块和路由器配置。
  • 你的意思是在 karma 中加载 angular-ui-router 是错误的?甚至加载http触发文件?
  • 您可以在 Karma 中加载它,它不会造成伤害。您只是不需要在规范中加载其模块。 IE。 mApp 不应该被加载,而是它的不依赖于 ui.router 模块的子模块应该被加载。每个 http 请求都应该被模拟。如果这个请求不是由当前规范中测试的单元完成的,那就不好了。
  • 我真的不知道它是如何工作的。但是当我将 scope.$apply 更改为 scope.$digest 时。一切都开始工作了。非常感谢您的帮助..请更改您的答案,以便我接受它。(如果您知道,请解释它的工作原理,以便对某人有所帮助)
猜你喜欢
  • 2012-05-20
  • 1970-01-01
  • 1970-01-01
  • 2014-01-16
  • 1970-01-01
  • 2015-09-20
  • 1970-01-01
  • 2015-03-22
  • 1970-01-01
相关资源
最近更新 更多