【问题标题】:How do I test angularjs directive to spy on the function call?如何测试 angularjs 指令以监视函数调用?
【发布时间】:2013-03-21 03:32:55
【问题描述】:

下面的代码执行但抱怨 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.

【问题讨论】:

    标签: javascript unit-testing angularjs jasmine


    【解决方案1】:

    更新:

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

    一般有两种方法可以解决这个问题:

    1. 监视某个功能,而不是由某些人触发的功能 事件/中介
    2. 在创建对象之前窥探函数的原型。换句话说:spyOn(MyObjectNamespace.Class.prototype, 'functionToSpyOn')

    之后只需恢复即可。


    我对 angular 只是隐约熟悉,但也遇到过类似的问题。

    解决方案 1

    您可以只分离函数而不是匿名指定它。这有助于专门测试您的功能并避免所有有角度的东西。

    解决方案 2

    有时使用框架是不可能的。这里的主要问题是您的 spy 附加自身太晚,并且引用丢失或被覆盖。

    测试:

    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 有一个 spy.restore 功能,可以为您摆脱第一行和最后一行。在我自己的测试中,我将第一行和间谍创建放在 beforeEach 中,将还原放在 afterEach 中。

    【讨论】:

    • 通过以这种方式重组代码,您正在测试指令的调用,而不是元素上的弹出函数。
    • @anazimok 好的,我改变了它......如果你现在调用 myPopOver 并提供了一个范围(null)、元素(一个 dom 元素)和 attr(有问题的 attr)。您实际上可以测试您的弹出框功能。这对我来说很有意义,因为您不想测试 Angular JS 的指令语句,而是您自己的代码。此外,您甚至不需要监视 myPopOver。您可以改为测试它的作用。这是一个更强的测试。
    • 感谢您的更新,但我认为您没有抓住重点。我不想测试我想测试的 myPopOver 函数 element.popover(...) 被调用。是的,我可以用不同的方式编写这个测试,但我想了解它为什么不起作用。 ;)
    • @anazimok 哈哈好吧!对不起。有一个更新让我知道这是否适合你。
    • @Paris Dude,您尝试获得 A+。但还是没有运气!
    【解决方案2】:

    我让它工作了。
    jquery和jquery popover js文件需要在测试时在angular.js之前加载。此顺序应在 testacular.conf.js 文件中指定。此外,http 的 url 缺少“/”。这是对我有用的代码:


    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();
        });
      });
    });
    

    【讨论】:

      猜你喜欢
      • 2016-12-07
      • 2014-01-13
      • 1970-01-01
      • 1970-01-01
      • 2017-07-13
      • 1970-01-01
      • 2016-05-28
      • 2015-07-26
      • 2015-01-11
      相关资源
      最近更新 更多