如何使用Jasmine窥探控制器方法?

时间:2015-02-25 22:10:08

标签: angularjs jasmine

我使用"控制器作为"语法来创建我的控制器。我有一个私有初始化函数,它调用一个函数来加载默认数据。

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

app.controller('MainCtrl', function($scope) {
  var mc = this;
  mc.dataLoaded = false;

  function init() {
    mc.loadData();
  }

  mc.loadData = function(){
    mc.dataLoaded = true;
  }

  init();
});

在我的测试中,我创建了一个间谍来检查是否已调用loadData函数。虽然我可以通过测试mc.dataLoaded标志来验证是否已调用该函数,但我的间谍似乎并没有记录被调用的函数。如何让间谍正确记录函数调用?

describe('Testing a Hello World controller', function() {
  var $scope = null;
  var ctrl = null;

  //you need to indicate your module in a test
  beforeEach(module('plunker'));

  beforeEach(inject(function($rootScope, $controller) {
    $scope = $rootScope.$new();

    ctrl = $controller('MainCtrl as mc', {
      $scope: $scope
    });

    spyOn($scope.mc, 'loadData').and.callThrough();
  }));

  it('should call load data', function() {
    expect($scope.mc.loadData).toHaveBeenCalled();
  //expect($scope.mc.dataLoaded).toEqual(false);
  });
});

Plunker link

2 个答案:

答案 0 :(得分:9)

这一系列的行:

ctrl = $controller('MainCtrl as mc', {
  $scope: $scope
});

spyOn($scope.mc, 'loadData').and.callThrough();

意味着在控制器已经由$ controller实例化之后创建了Jasmine间谍。在创建间谍之前,init函数已经执行。

你不能切换任何一条线,因为MainCtrl需要存在才能监视它上面的方法。

如果init函数调用另一个服务,则监视该服务的方法并声明该服务被正确调用。如果MainCtrl只是在内部执行某些操作,那么请测试其结果,例如,断言控制器的数据/属性已更新。如果它足够微不足道,它甚至可能不值得测试。

此外,由于您使用控制器作为语法,您可以通过调用$ controller的返回值来引用控制器,而不是直接访问范围:

ctrl = $controller('MainCtrl as mc', {
  $scope: $scope
});

ctrl.loadData === $scope.mc.loadData; // true

答案 1 :(得分:1)

我找到了一个允许我避免更换控制器的解决方案。我在测试套件的$state方法中添加了beforeEach模拟服务,并为其提供了reload模拟方法:

beforeEach(inject(function ($controller, $rootScope) {
    stateMock = {
        reload: function() {
            myCtrl = $controller('MyCtrl');
        }
    };
    ...

然后在茉莉花测试中,我可以简单地调用stateMock.reload()来重新初始化我的控制器,同时保留我在另一个beforeEach块中声明的间谍。