如何测试angularjs指令以窥探函数调用?

时间:2013-03-30 15:17:21

标签: javascript unit-testing angularjs jasmine

下面的代码执行但抱怨没有调用element.popover。我似乎无法弄清楚问题是什么。

提前感谢您的帮助。

指令:

angular.module('directives', []).

directive('popOver', function ($http) {

    return {
        restrict:'C',

        link: function (scope, element, attr) {
            element.bind('mouseover', function (e) {
                $http.get("someurl" + attr.chatid + ".json").success(function (data) {
                    element.popover({content: data.firstName + " " + data.lastName });
                });
            });
        }
    }
})

茉莉花测试:

'user strict'

describe('directives', function() {
    beforeEach(module('directives'));
    describe('popOver', function() {
    var $scope, compile, location,  $httpBackend, elm;

    beforeEach(inject(function($rootScope, $compile, _$httpBackend_) {
        $scope = $rootScope.$new();
        compile = $compile;
        $httpBackend = _$httpBackend_;
        elm = angular.element('<i class="pop-over" data-placement="top" data-chatid="testChatId" > </i>');
        compile(elm)($scope);

    }));

    it('should call element.popover()', function() {
        $httpBackend.expectGET('someurl/testChatId.json').
            respond([ {firstName: 'test', lastName: 'user'}]);

        spyOn(elm, 'popover').andCallThrough();

        elm.trigger('mouseover');
        $httpBackend.flush();

        expect(elm.popover).toHaveBeenCalled();
    });
  });
});

输出:

Chrome 26.0 (Mac) directives popOver should call element.popover() FAILED
Expected spy popover to have been called.
Error: Expected spy popover to have been called.

2 个答案:

答案 0 :(得分:8)

更新

我无法解决您的具体问题。主要是因为我无法获得角度种子/它永远消失,但我想我会让我的答案更完整。

通常有两种方法可以解决这个问题:

  1. 监视除某人触发之外的其他功能 事件/媒介
  2. 在创建对象之前监视函数的原型。换句话说:spyOn(MyObjectNamespace.Class.prototype, 'functionToSpyOn')
  3. 然后恢复,你应该没事。


    我只是模糊地熟悉角度,但也经历过类似的问题。

    解决方案1 ​​

    您可以将功能分开,而不是匿名指定。这有助于专门测试您的功能并避免所有有角度的东西。

    解决方案2

    有时使用框架这是不可能的。这里的主要问题是你的间谍附加太晚而且引用丢失或被覆盖。

    测试:

    describe('directives', function() {
        beforeEach(module('directives'));
        describe('popOver', function() {
        var $scope, compile, location,  $httpBackend, elm;
    
        beforeEach(inject(function($rootScope, $compile, _$httpBackend_) {
            $scope = $rootScope.$new();
            compile = $compile;
            $httpBackend = _$httpBackend_;
            elm = angular.element('<i class="pop-over" data-placement="top" data-chatid="testChatId" > </i>');
            compile(elm)($scope);
    
        }));
    
        it('should call element.popover()', function() {
            var popoverFunction = $.fn.popover;
            $httpBackend.expectGET('someurl/testChatId.json').
                respond([ {firstName: 'test', lastName: 'user'}]);
    
            spyOn($.fn, 'popover').andCallThrough();
    
            elm.trigger('mouseover');
            $httpBackend.flush();
    
            expect($.fn.popover).toHaveBeenCalled();
            //restore popover, use sinon's restore fn instead here
            $.fn.popover = popoverFunction
        });
      });
    });
    

    你可以将Sinon与Jasmine一起使用。 Sinon有一个spy.restore函数,可以为你排除第一行和最后一行。在我自己的测试中,我将第一行和间谍创建放在beforeEach中,并在afterEach中进行恢复。

答案 1 :(得分:5)

我得到了它的工作。
在测试期间,需要在angular.js之前加载jquery和jquery popover js文件。此命令应在testacular.conf.js文件中指定。此外,http的网址缺少'/'。以下代码对我有用:


angular.module('directives', []).

directive('popOver', function($http) {

  return {
    restrict: 'C',

    link: function(scope, element, attr) {
      element.bind('mouseover', function(e) {
        $http.get("someurl/" + attr.chatid + ".json").success(function(data) {
          element.popover({
            content: data.firstName + " " + data.lastName
          });
        });
      });
    }
  }
})



'user strict'

describe('directives', function() {
  beforeEach(module('directives'));
  describe('popOver', function() {
    var $scope, compile, location, $httpBackend, elm;

    beforeEach(inject(function($rootScope, $compile, _$httpBackend_) {
      $scope = $rootScope.$new();
      compile = $compile;
      $httpBackend = _$httpBackend_;
      elm = angular.element('<i class="pop-over" data-placement="top" data-chatid="testChatId" > </i>');
      compile(elm)($scope);

    }));

    it('should call element.popover()', function() {
      $httpBackend.expectGET('someurl/testChatId.json').
      respond([{
        firstName: 'test',
        lastName: 'user'
      }]);
      //spyOn(elm, 'popover').andCallThrough();
      spyOn($.fn, 'popover').andCallThrough();

      elm.trigger('mouseover');
      $httpBackend.flush();

      //expect(elm.popover).toHaveBeenCalled();
      expect($.fn.popover).toHaveBeenCalled();
    });
  });
});