【问题标题】:Unit Testing Angular Code with a Service using Jasmine使用 Jasmine 对 Angular 代码进行单元测试
【发布时间】:2015-01-20 23:24:55
【问题描述】:

我正在尝试测试一个控制器,而不是要求我模拟我用来获取数据的服务。目前我收到一条错误消息,提示此行上的函数未定义:

dataServiceMock = jasmine.createSpyObj('dataService', ['getFunctionStuff']);

根据其他示例和教程,这应该可以正常工作。

这是我的代码,包括测试文件、服务和控制器。

控制器:

var app = angular.module('myApp', []);

app.controller('MainCtrl', function($scope, dataService) {

    dataService.getFunctionStuff($scope.foo)
      .then(function(data) {
        $scope.test = data;
      });

});

服务:

app.factory('dataService', function ($timeout, $q){

  function getFunctionStuff(formData) {
            return $http.post('../randomAPICall', formData).then(function(data) {
                return data;
            });
        };

});

测试:

describe('Testing a controller', function() {
  var $scope, ctrl, $timeout;

  var dataServiceMock;

  beforeEach(function (){

    dataServiceMock = jasmine.createSpyObj('dataService', ['getFunctionStuff']);

    module('myApp');

    inject(function($rootScope, $controller, $q, _$timeout_) {

      $scope = $rootScope.$new();

      dataServiceMock.getFunctionStuff.and.ReturnValue($q.when('test'));

      $timeout = _$timeout_;

      ctrl = $controller('MainCtrl', {
        $scope: $scope,
        dataService: dataServiceMock
      });
    });
  });

  it('should update test', function (){
    expect($scope.test).toEqual('test');    
  });
});

这是它的一个小插曲:http://plnkr.co/edit/tBSl88RRhj56h3Oiny6S?p=preview

【问题讨论】:

  • 我已经发布了两种进行单元测试的方法。一种是你创建间谍的方式,另一种是使用$httpBackend,这是一种常见的方式。

标签: angularjs unit-testing jasmine


【解决方案1】:

当您使用 jasmine 2.1 时,API 是 .and.returnValue。在您的测试规范中,在then 之前执行$scope.$apply()

describe('Testing a controller', function () {
    var $scope, ctrl, $timeout;

    var dataServiceMock;

    beforeEach(function () {

        dataServiceMock = jasmine.createSpyObj('dataService', ['getFunctionStuff']);

        module('myApp');

        inject(function ($rootScope, $controller, $q, _$timeout_) {

            $scope = $rootScope.$new();

            dataServiceMock.getFunctionStuff.and.returnValue($q.when('test'));

            $timeout = _$timeout_;

            ctrl = $controller('MainCtrl', {
                $scope: $scope,
                dataService: dataServiceMock
            });
        });
    });

    it('should update test', function () {
        $scope.$apply();
        expect($scope.test).toEqual('test');
    });
});

【讨论】:

  • 你能解释一下为什么我需要使用 $scope.$apply() 吗?我试过了,效果很好,我想了解一下。
  • @Blake - 您需要使用 $apply() 将 promise 解析传播到“then”函数。参考angular $q document
【解决方案2】:

这是$httpBackend 测试$http 的另一种常用方法:

app.js

var app = angular.module('myApp', []);

app.controller('MainCtrl', function($scope, dataService) {

    dataService.getFunctionStuff($scope.foo)
      .then(function(data) {
        $scope.test = data.data;
      });

});

dataService.js

app.factory('dataService', function($http) {

  function getFunctionStuff(formData) {
    return $http.post('../randomAPICall', formData).then(function(data) {
      return data;
    });
  }

  return {
    getFunctionStuff: getFunctionStuff
  };

});

specs.js

describe('Testing a controller', function() {
  var $scope, ctrl, $controller, $httpBackend;

  beforeEach(function (){

    module('myApp');

    inject(function($injector) {

      $httpBackend = $injector.get('$httpBackend');
      $scope = $injector.get('$rootScope').$new();
      $controller = $injector.get('$controller');

      $scope.foo = 'foo';
      $httpBackend.expectPOST('../randomAPICall', 'foo').respond(201, 'test');
      ctrl = $controller('MainCtrl', {$scope: $scope});
    });

  });

  it('should update test', function (){
    expect($scope.test).not.toBeDefined();
    $httpBackend.flush();
    expect($scope.test).toEqual('test');    
  });
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-08-14
    • 1970-01-01
    • 1970-01-01
    • 2023-01-13
    • 2021-09-10
    • 2023-03-18
    • 2014-08-15
    • 1970-01-01
    相关资源
    最近更新 更多