AngularJS + Karma:在单元测试指令或控制器时重用模拟服务

时间:2013-05-15 11:35:21

标签: angularjs unit-testing jasmine karma-runner code-reuse

我正在使用AngularJS + Karma。 configService管理我的应用程序的设置(例如背景颜色,它在调试模式下,一般权限......)。它使用$ http加载初始数据。我成功地为服务编写了测试,但我的指令和控制器使用它。

当我为指令编写单元测试时,我必须模拟服务。

我知道我能做到:

spyOn(configService, 'getBackgroundColor').andCallFake(function (params) {
   return "red";
});

但该服务有25多种方法和初始数据加载。我不想在每个测试套件中编写(并维护)这个spyOn的东西。更重要的是,我使用$ http在工厂加载数据,这也应该被嘲笑。如果我只是注入服务并模拟调用,我仍然会发出http get请求。

您认为重用模拟的最佳方式是什么?

2 个答案:

答案 0 :(得分:9)

您可以在自己的模块中创建适当的服务模拟,并将其添加到需要它的任何测试中,而不是使用间谍来喷涂测试代码。

控制器单元测试位于test / spec / modules / user / controller.js文件中。

模拟服务位于test / mock / modules / user / service.js文件中。

对于控制器方法:

$scope.refreshList = function() {
  UserService.all(pageNumber, size, sort, function(data) {
    $scope.users = data.content;
    $scope.page = data.page;
  });
};

模拟服务:

(function () {

'use strict';

angular.module('app.user.mock', ['app.user']);

angular.module('app.user.mock').factory('UserServiceMock',
  ['$q',
  function($q) {
    var factory = {};

    factory.mockedUsers = { 
      content: [ { firstname: 'Spirou', lastname: 'Fantasio', email: 'spirou@yahoo.se', workPhone: '983743464365' } ],
      page: '1'
    };

    factory.search = function(searchTerm, page, size, sort, callback) {
      var defer = $q.defer();
      defer.resolve(this.mockedUsers);
      defer.promise.then(callback);
      return defer.promise;
    };

    factory.all = function(page, size, sort, callback) {
      var defer = $q.defer();
      defer.resolve(this.mockedUsers);
      defer.promise.then(callback);
      return defer.promise;
    };

    return factory;
  }
]);

})();

和控制器单元测试:

(function () {

'use strict';

var $scope;
var listController;
var UserServiceMock;

beforeEach(function() {
  module('app.project');
  module('app.user.mock'); // (1)
});

beforeEach(inject(function($rootScope, _UserServiceMock_) {
  $scope = $rootScope.$new();
  UserServiceMock = _UserServiceMock_; // (2)
}));

describe('user.listCtrl', function() {

  beforeEach(inject(function($controller) {
    listController = $controller('user.listCtrl', {
      $scope: $scope,
      UserService: UserServiceMock
    });
  }));

  it('should have a search function', function () { // (3)
    expect(angular.isFunction(UserServiceMock.search)).toBe(true);
  });

  it('should have an all function', function () {
    expect(angular.isFunction(UserServiceMock.all)).toBe(true);
  });

  it('should have mocked users in the service', function () {
    expect(UserServiceMock.mockedUsers).toBeDefined();
  });

  it('should set the list of users in the scope', function (){
    expect($scope.users).not.toEqual(UserServiceMock.mockedUsers);
    $scope.refreshList();
    $scope.$digest();
    expect($scope.users).toEqual(UserServiceMock.mockedUsers.content);
  });

});

})();

添加包含模拟服务的app.user.mock模块(1)并在控制器(2)中注入模拟服务。

然后,您可以测试已经注入的模拟服务(3)。

答案 1 :(得分:0)

  

我创建了一个.js文件,它只包含一个简单的旧javascript函数,我调用它来创建mock。另一个普通的旧javascript函数来配置服务器响应以进行测试。就像你说的那样,如果用json响应定义一个全局变量,那么你可以在测试中使用它来比较