Jest测试EventEmitter事件处理时sock.send调用次数为0如何解决
问题根因
测试失败的核心原因是测试用例中调用initializer.zmqSock()和initializer.wsClient()拿到的是全新实例,和app.js初始化时绑定逻辑的实例完全无关:
- app.js在被require加载的阶段,就已经调用一次
initializer.zmqSock()和initializer.wsClient()生成了内部使用的sock、ws实例,并且给该ws绑定了update事件监听 - 测试用例中第二次调用两个方法返回的是新的EventEmitter和zmq实例,给新的ws emit事件无法触发app中绑定的监听逻辑,新sock的send方法自然不会被调用
最优实现方案
直接从mock函数的调用记录中取app初始化时生成的实例即可,不需要重新调用生成新实例:
const initializer = require("./dependencyInitializer"); jest.mock("./dependencyInitializer", () => { return { wsClient: jest.fn(() => { const EventEmitter = require("events") return new EventEmitter() }), zmqSock: jest.fn(() => { return { send: jest.fn() } }) } }); // mock完成后再引入app,保证app拿到的是mock后的实例 require("./app"); describe('on message received from websocket',() => { it('should pass it to zmq', () => { // 直接取app初始化时生成的实例,不需要重新调用方法 const appWs = initializer.wsClient.mock.results[0].value; const appSock = initializer.zmqSock.mock.results[0].value; const testData = {topic: "test_topic", result: "ok"}; // 给app实际绑定监听的ws实例emit事件 appWs.emit("update", testData); // 支持同时校验调用次数和参数,逻辑更严谨 expect(appSock.send).toHaveBeenCalledTimes(1); expect(appSock.send).toHaveBeenCalledWith([testData.topic, JSON.stringify(testData)]); }); });
额外优化建议
如果存在多个测试用例,可以在beforeEach中重置mock的调用记录,并且重新require app,避免用例之间的状态互相影响。
内容的提问来源于stack exchange,提问作者Luca Rosellini
相关产品推荐
相关产品推荐

