如何模拟在控制器初始化时运行的函数

How to mock a function that runs on controller initialization?

本文关键字:初始化 运行 函数 控制器 何模拟 模拟      更新时间:2023-09-26

>Controller:

function myCtrl($scope) {
    $scope.firstFn = function() {
        console.log('firstFn called');
        $scope.test1 = 2;
    };
    $scope.secondFn = function() {
        console.log('secondFn called');
        $scope.test2 = 3;
    };
    (function constructor() {
        console.log('Controller init.');
        $scope.test1 = 1;
        $scope.test2 = 2;
        $scope.firstFn();
    })();
};

是否可以在不执行"firstFn"的情况下为名为"secondFn"的函数编写单元测试?可以嘲笑它什么的吗?

scope = $rootScope.$new();
ctrl = $controller('myCtrl', {$scope: scope});
// Mock firstFn ?
scope.secondFn();
// assert $scope.test1 = 1
// assert $scope.test2 = 3

您将需要:

  1. 在创建控制器之前$scope上创建firstFn的模拟版本
  2. 防止控制器更换模拟

除非你正在测试像IE8这样的旧浏览器,否则你可以通过使用Jasmine的createSpy和ECMAScript 5方法Object.defineProperty()来实现这一点。

请注意,以下示例使用的是 Jasmine 2.0。

创建模拟:

firstFnMock = jasmine.createSpy('firstFn').and.callFake(function() {
  console.log('firstFnMock called');
});

使用 defineProperty 在名为 firstFn $scope上创建属性,并将其值设置为模拟函数:

Object.defineProperty($scope, "firstFn", {
  enumerable: false,
  configurable: false,
  writable: false,
  value: firstFnMock
});
请务必将

writable设置为false,因为它将阻止控制器更换模拟。

往常一样在创建控制器时使用准备好的$scope(在此示例中设置创建控制器的函数):

createController = function() {
  return _$controller_('MyController', {
    $scope: $scope
  });
};

规格示例:

it('Spec', function() {
  createController();
  expect(firstFnMock).toHaveBeenCalled();
  $scope.secondFn();
  expect($scope.test1).toBe(1);
  expect($scope.test2).toBe(3);
});

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

只是监视firstFn.默认情况下,对监视函数的任何调用都将是针对 Jasmine 间谍对象,而不是实际函数。

scope = $rootScope.$new();
ctrl = $controller('myCtrl', {$scope: scope});
spyOn(scope, 'firstFn');
scope.secondFn();
// assert $scope.test1 = 1
// assert $scope.test2 = 3

有关对间谍行为的更多控制,请参阅 http://jasmine.github.io/2.0/introduction.html#section-Spies