【问题标题】:Jasmine - Check if service method within a controller method was calledJasmine - 检查是否调用了控制器方法中的服务方法
【发布时间】:2017-07-13 13:32:09
【问题描述】:

一天前我开始使用 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(); 
    });
});

这当然行不通。错误日志告诉我创建一个间谍对象。所以我做了...

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

没有帮助,所以我打电话给

dataService.fetchValues('dataprotection');

就在“scope.init();”之后。首先期望通过。

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

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

【问题讨论】:

  • 您使用的是什么版本的 Jasmine? 1.3 还是 2.0?

标签: angularjs testing jasmine


【解决方案1】:

以下语法适用于 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后需要手动触发一个digest来获取promise的resolve:

$scope.init();

$scope.$digest();

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

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

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

【讨论】:

    猜你喜欢
    • 2019-06-06
    • 2014-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多