10

尝试使用 Jasmine 测试在单击的元素上调用事件处理程序。有一个“Pad”对象,其中包含一个被点击的 DOM 元素“PadElement”。事件处理程序是 Pad 对象上的一个方法:

GRAPH.Pad = function(graphDiv, graph) {
    this.graph = graph;

    this.clickHandler = function(e) {
        console.log('padElement clickHandler called');
        //this.graph.createVertex(e.clientX, e.clientY);
    };
    this.padElement = GRAPH.padElement(graphDiv, this.clickHandler);
}

GRAPH.padElement = function(graphDiv, clickHandler) {
    //Initialize pad
    var NS="http://www.w3.org/2000/svg";
    var pad=document.createElementNS(NS,"svg");
    pad.setAttributeNS(null, 'id', 'pad');
    graphDiv.appendChild(pad);
    pad.addEventListener('click', clickHandler)
    return pad;
}

茉莉花测试:

var testDiv = document.createElement('div');
var testGraph = new GRAPH.Graph(testDiv);
var testPad = new GRAPH.Pad(testDiv, testGraph);

  it('has its clickHandler function called when its padElement is clicked',
    function() {
      spyOn(testPad, "clickHandler");
      simulateClick(testPad.padElement);
      //testPad.clickHandler();
      expect(testPad.clickHandler).toHaveBeenCalled();
  });

但是,测试失败。请注意,事件侦听器确实被调用(console.log 通过鼠标单击和模拟单击成功写入),并且如果我直接调用 testPad.clickHandler(),Jasmine 的间谍可以拾取它。但是在实际测试中会发生什么?事件处理程序调用是否在运行时转移到不同的对象?这样做的正确方法是什么?

4

2 回答 2

6

您实际上是在测试GRAPH.padElement调用提供的clickHandler而不是调用this.clickHandler的。我会怎么做GRAPH.PadGRAPH.padElement

var testDiv = document.createElement('div');
var clickHandlerSpy = jasmine.CreateSpy();
var padelement = padElement(testDiv , clickHandlerSpy);

  it('has its clickHandler function called when its padElement is clicked',
    function() {
      simulateClick(testPad.padElement);
      expect(clickHandlerSpy).toHaveBeenCalled();
  });

这听起来可能与您想要实现的目标没什么不同。但是在理想的单元测试世界中,您应该独立测试每个单元,所以我会首先测试padElement它应该做的事情(如上所述),然后编写另一个测试以确保GRAPH.Pad将正确的处理程序传递给padElement. 现在要做到这一点,我不会padElement直接从内部创建,GRAPH.Pad而是以某种方式从外部注入它,然后在茉莉花规格中模拟它。如果您对这部分不清楚,请告诉我,我可以为您整理一些代码。

于 2012-05-02T14:37:14.600 回答
3

添加更通用的解释:

在将函数附加为事件侦听器之前,您需要进行间谍活动

一些伪代码:

it("succeeds", function(){
  var o = {}
  o.f = function() { console.log("event caught!");} //your eventHandler
  spyOn(o, "f").and.callThrough(); //o.f is now a spy
  addEventListener('click', o.f); //spy listens for event 

  fireEvent("click"); //"event caught!" is written to console

  expect(o.f).toHaveBeenCalled(); //success, we're happy
});



it("fails", function(){
  var o = {}
  o.f = function() { console.log("event caught!");} //your eventHandler
  addEventListener('click', o.f); //your eventHandler function listens for event
  spyOn(o, "f").and.callThrough(); //o.f is now a spy

  fireEvent("click"); //"event caught!" is written to console

  expect(o.f).toHaveBeenCalled(); //fail, we waste a couple of hours not understanding why
});

因此,如果您知道正在调用您的处理程序,但间谍没有注册为.tohaveBeenCalled()检查首先发生的事情:您的间谍或侦听器的分配。间谍需要先来。

于 2016-09-08T13:40:58.153 回答