【问题标题】:Spying on JQuery Selectors in Jasmine在 Jasmine 中监视 JQuery 选择器
【发布时间】:2011-07-17 06:52:41
【问题描述】:

我正在使用 Jasmine 对一些 JavaScript 进行单元测试,并希望监视(模拟)由 jQuery 选择器访问的 DOM 元素。

我的规格是:

it("should be able to mock DOM call", function() {

    spyOn($("#Something"), 'val').andReturn("bar");

    result = $("#Something").val();

    expect(result).toEqual("bar");

});

在我的 specrunner.html 中有:

<input type="hidden" id="Something" value="foo" />

不幸的是,规范失败了:

应该能够模拟 DOM 调用 Expected 'foo' to equal 'bar'。

【问题讨论】:

    标签: jquery unit-testing jasmine


    【解决方案1】:

    这一行是错误的:

    spyOn($("#Something"), 'val').andReturn("bar");
    

    Jasmine 的 spyOn 函数需要两个参数。第一个是现有对象。第二个是作为字符串的函数名。您正确地将函数名称作为字符串(“val”)传递,但您没有将现有对象作为第一个参数传递。

    $("#Something")
    

    ...不是现有对象。它是 jQuery 选择器的结果(返回值)。更具体地说,它将返回一个代表匹配节点的 jQuery 对象——有点像结果数组。

    $
    

    ...是一个现有的对象。

    $.fn
    

    ...是一个现有的对象。

    $("#Something")
    

    ...不是现有对象 - 它是 jQuery 选择器的结果

    这将起作用:

    it("should be able to mock DOM call", function () {
        //spyOn($.fn, "val").andReturn("bar"); //pre-jasmine 2.0 syntax
        spyOn($.fn, "val").and.returnValue("bar"); //Jasmine 2.0 Syntax
        var result = $("#Something").val();
        expect(result).toEqual("bar");
    });
    

    【讨论】:

    • 我也很困惑。 var $foo = $('#foo')。现在$foo 是一个现有对象:它是一个jQuery 对象。它有一个val() 方法;它只是通过查找其原型链到jQuery.fn 来获得它。那我为什么不能spyOn($foo, "val")呢?为什么 Jasmine 的 spy 要求我指定方法的定义位置?我的用例是我想检查hide() 是否已被调用,不仅仅是一般情况下,而是在$foo 上。所以spyOn(jQuery.fn, "hide") 没有给我我想要的信息,但spyOn($foo, "hide") 会 - 如果它有效。
    • @NathanLong 是对的 - 这是错误的答案。我不知道为什么它的投票率这么高..
    • @NathanLong 问题是每次执行 jquery 选择器时,都会得到一个全新的对象,因此您设置的用于监视的对象将与您在正在测试的代码。因此,Alex 告诉您监视所有 jquery 对象的原型 ($.fn)。
    • @badunk 它的投票率很高,因为它回答了以下问题:“当我使用 jQuery('foo') 时实际调用了什么”;)
    • 嗨,你能帮我看看 jQuery 的 BLOCK 方法吗,我无法在 Jasmine/Sinon 测试用例中检查它的调用计数...
    【解决方案2】:

    看来我找到了很好的解决方案

        it "should open past statuses", ->
          # We can't use $('.past') here cause each time $('.past') called it returns different objects
          # so we need to store spy in variable
          showSpy = spyOn($.fn, 'show')
          # do the stuff
          $('.show-past').click()
          # then check if 'show' action was called
          expect($.fn.show).toHaveBeenCalled()
          # and if it realy our object
          expect(showSpy.mostRecentCall.object.selector).toEqual('.past')
    

    这不是基于您的代码,但我希望这可以帮助某人。而且,是的,CoffeScript 中的示例。

    【讨论】:

    • .selector 在 jQuery 1.7+ 中已弃用。 1.7+ 版本中的替代方案是什么?
    【解决方案3】:

    问题在于对 $ 的两次调用返回两个不同的 jQuery 包装节点。

    这应该可行:

    it("should be able to mock DOM call", function(){
    
      // var node = $("Something");
      // spyOn(node, 'val').andReturn('bar');
    
      // expect(node.val()).toEqual('bar');
      var node = $("Something");
      spyOn(node, 'val').and.returnValue('bar');
    
      expect(node.val()).toEqual('bar');
    });
    

    下次,Jasmine 邮件列表中的帮助会更加普遍:jasmine-js@googlegroups.com。

    【讨论】:

    • 这是你的答案,jQuery 为每个查询返回一个不同的对象,即使它是相同的选择器。您需要引用同一个对象才能正确监视它。否则,您就是在监视一个,并执行另一个。
    • 试试这个期望:expect(node.val).toHaveBeenCalled()
    【解决方案4】:

    您可以创建自己的假 DOM 元素,然后像往常一样使用 $('#elementid')[0]

    addFakeElementWithId = function (elementId) {
          var fake = document.createElement("div");
          fake.setAttribute("id", elementId);
          document.body.appendChild(fake);
       };
    

    【讨论】:

      【解决方案5】:

      我写了一个辅助函数,它接受一个 id/value-pairs 数组。

      var jasminTestHelper = {
          spyOnValAndFake : function(obj) {
              var i, j;
              spyOn($.fn, 'val').andCallFake(function() {
                  for ( i = 0, j = obj.length; i < j; i++) {
                      if (this.selector === '#' + obj[i][0]) {
                          return obj[i][1];
                      }
                  }
              })
          }
      }
      

      每一对都告诉 faker-function 哪个 id,如果 jQuery-val()-function 使用 id-selector 调用,应该返回哪个值。它是这样使用的:

      jasminTestHelper.spyOnValAndFake([["id1", "value1"], ["id2", "value2"]]);
      

      如果在您的测试函数中调用$('#id1').val(),则伪函数返回value1,如果调用$('#id2').val(),则返回value2。所以你不需要摆弄 DOM,你只需模拟 jQuery-val() 函数并模拟返回值。其他 jQuery 函数可能会以同样的方式进行模拟。

      【讨论】:

      【解决方案6】:

      我认为我的 jasmine 版本 (2.0.3) 发生了变化,因此 Alex York 的解决方案没有按原样工作,但肯定给了我一条道路。所以这是工作规范 要测试的jquery代码

      $('someSelector').data('someAttribute').enable();
      

      这是它的茉莉花规格部分

      var mockJqueryObject = { enable:function(){},disable:function(){}};
      //this mocks the .data('someAttribute') in above code.
      spyOn($.fn, "data").and.returnValue(mockSelectBoxObject); 
      

      更细粒度的规范可以使用另一个级别的模拟

      spyOn(mockJqueryObject,"enable")
      spyOn(mockJqueryObject,"disable")
      

      【讨论】:

        猜你喜欢
        • 2015-09-17
        • 1970-01-01
        • 2013-01-09
        • 2016-05-06
        • 2011-04-11
        • 1970-01-01
        • 2016-04-28
        • 2012-06-13
        相关资源
        最近更新 更多