无法在测试中模拟事件处理程序

Unable to mock event handler on test

所以我有一个非常简单的 class,它执行以下操作:

export default class TestClass {
  constructor() {
    this.element = document.getElementById("test");
    this.element.addEventListener("click", this.clickHandler);
  }

  clickHandler(e) {
    console.log("Click handler called");
  }

  cleanup() {
    this.element.removeEventListener("click", this.clickHandler);
  }
}

我有一个测试,其中我 stub 处理程序(我需要更改它的行为)并进行一些检查。

describe("Test", function () {
  beforeEach(function () {
    this.instance = new TestClass();
    this.clickHandlerStub = sinon.stub(this.instance, "clickHandler");
  });

  afterEach(function () {
    this.instance.cleanup();
    delete this.instance;
  });

  it("test case", function () {
    document.getElementById("test").click();
    expect(this.clickHandlerStub.calledOnce).to.equal(true);
  });
});

预期的行为是 stub(覆盖)处理程序(因此不应出现日志记录)并且我的期望应该通过,因为它应该在单击元素时调用一次。 但是它似乎一直在记录并且期望失败。

如果我改变绑定事件处理程序的方式并使用箭头函数,一切正常。

this.element.addEventListener("click", () => this.clickHandler());

但是我无法删除 cleanup 方法中的事件处理程序,因为 addEventListenerremoveEventListener 需要传递相同的处理程序引用才能正常工作。

我创建了一个 reproducable example in codesandbox 以防有帮助。

那么我在这里错过了什么?

您可以stub TestClass原型

this.clickHandlerStub = sinon
  .stub(TestClass.prototype, "clickHandler")
  .callsFake(() => {
    console.log(`Now it's calling the fake handler`);
  });

清理将是

this.clickHandlerStub.restore();

https://codesandbox.io/s/mocha-unit-test-example-forked-sstfz?file=/src/index.js

参考文献:

  • Restore sinon stub

顺便说一下,我不喜欢在全局上下文中使用 this。相反,我将它们创建为 let 变量。

describe('...', () => {
  let clickHandlerStub;

  beforeEach(() => {
    clickHandlerStub = ...
  });

  afterEach(() => {
    clickHandlerStub.restore();
  });
});