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

err*_*337 2 testing jasmine angularjs

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

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

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

我的测试应该如下所示:

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(); 
    });
});
Run Code Online (Sandbox Code Playgroud)

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

spyOn(dataService, 'fetchValues').andCallThrough();
Run Code Online (Sandbox Code Playgroud)

没有帮忙,所以我打电话

dataService.fetchValues('dataprotection');
Run Code Online (Sandbox Code Playgroud)

就在"scope.init();"之后.首先期待通过.

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

对不起,如果这是一个非常愚蠢的问题,但我确实被卡住了...感谢您的帮助!

tas*_*ATT 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_;
}));
Run Code Online (Sandbox Code Playgroud)

请注意,如果您使用and.callThrough()spy会将函数调用委托给实际fetchValues实现,除非您自己将其替换为模拟函数.

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

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

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

DataService.fetchValues('dataprotection')
Run Code Online (Sandbox Code Playgroud)

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

.then(function(result) { ...
Run Code Online (Sandbox Code Playgroud)

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

$scope.init();

$scope.$digest();
Run Code Online (Sandbox Code Playgroud)

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

expect(DataService.fetchValues).toHaveBeenCalledWith('dataprotection');
Run Code Online (Sandbox Code Playgroud)

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