Jasmine - 检查控制器方法中的服务方法是否被调用

时间:2014-11-10 16:42:47

标签: angularjs testing jasmine

我前一天开始用Jasmine测试我的ionic / angularjs应用程序。我不确定我是否完全误解了测试的想法,但我想测试控制器方法中的服务方法是否被调用以及控制器如何对返回的任何内容作出反应。

我想测试的控制器功能如下:

$scope.init = function() {
    DataService.fetchValues('dataprotection').then(function (result) {
        $scope.dataprotection = result;
    }, function (failure) {
        $scope.dataprotection = 'No dataprotection available';
    });
};

我的测试应该如下所示:

describe('DataprotectionController', function () {
    beforeEach(inject(function ($rootScope, $controller, DataService) {
        scope = $rootScope.$new();
        controller = $controller('DataprotectionCtrl', {
            '$scope': scope
        });

        dataService = DataService;
    }));

    it('Should init dataprotection on startup', function () {
        // call init function in controller
        scope.init();
        //check if dataservice.fetchValues have been called with 'dataprotection' as parameter
        expect(dataService, 'fetchValues').toHaveBeenCalledWith('dataprotection');
        //calling fetchValues should init scope.dataprotection variable
        expect(scope.dataprotection).toBeDefined(); 
    });
});

当然这不起作用。 Errorlogs告诉我创建一个间谍对象。所以我做了......

spyOn(dataService, 'fetchValues').andCallThrough();

没有帮助所以我正在打电话

dataService.fetchValues('dataprotection');

紧跟在“scope.init();”之后。首先期待通过。

我真正不理解的是:为什么我要为dataService fetchValues()方法创建一个间谍对象,然后用参数调用它并检查它是否用给定的参数调用?我不想手动调用它,我想检查是否在DataprotectionController的scope.init()函数内调用了dataService.fetchValues('dataprotection')。

很抱歉,如果这是一个非常愚蠢的问题,但我确实被卡住了...... 谢谢你的帮助!

1 个答案:

答案 0 :(得分:6)

以下语法适用于Jasmine 2.0,因此如果您使用的是Jasmine 1.3,则需要进行一些小的更改。

首先,您需要将DataService注入控制器:

var $scope,
    DataService,
    $q;

beforeEach(module('myApp'));

beforeEach(inject(function($controller, $rootScope, _DataService_, _$q_) {

  $scope = $rootScope.$new();
  DataService = _DataService_;

  controller = $controller('DataprotectionCtrl', {
    '$scope': $scope,
    'DataService': DataService
  });

  $q = _$q_;
}));

请注意,如果使用and.callThrough(),间谍会将函数调用委托给真正的fetchValues实现,除非您自己用模拟函数替换它。

您可以使用and.callFake返回承诺:

spyOn(DataService, 'fetchValues').and.callFake(function(input) {
    var deferred = $q.defer();
    deferred.resolve('mock');
    return deferred.promise;
});

否则控制器中的以下代码将不会返回任何内容:

DataService.fetchValues('dataprotection')

这意味着它会尝试在undefined上执行以下操作:

.then(function(result) { ...

使用ngMock时,您需要同步维护测试流程,因此在调用init之后,您需要手动触发摘要以获得解决的承诺:

$scope.init();

$scope.$digest();

最后验证服务函数被调用的语法是:

expect(DataService.fetchValues).toHaveBeenCalledWith('dataprotection');

演示: http://plnkr.co/edit/Pslme1Ve1M1E6hbm1J6D?p=preview