用玩笑模拟自定义事件发射器

Posted

技术标签:

【中文标题】用玩笑模拟自定义事件发射器【英文标题】:Mock a custom event emitter with jest 【发布时间】:2020-05-14 08:56:01 【问题描述】:

我想断言 EventEmitter 类的发射是使用 Jest 使用特定参数调用的。我有一个单独的文件,在其中创建要使用的 eventEmitter 实例,并在另一个类上导入它,并在某个时候发出事件。

// commonEmitter.ts
const events = require('events');
export const commonEmitter = new events.EventEmitter();

// class.ts
import  commonEmitter  from (..)

export class MyClass 
   (...)       

   method()
     commonEmitter.emit('eventName',  data: true);
   


// class.spec.ts

let commonEmitterMock: any

beforeEach(() => 
  commonEmitterMock = createMock('emit');
);


it('testMyClass', async () => 
   const method = new MyClass().method();
   expect(commonEmitterMock).toHaveBeenCalledWith('eventName',  data: true)

有了这个实现,发射事件永远不会被调用.. 不知道为什么,有什么想法吗?

【问题讨论】:

【参考方案1】:

最好注入依赖项以使您的类更具可测试性,而不是导入它。所以你的班级看起来像

export class MyClass 
   constructor(commonEmitter) 
     this.commonEmitter_ = commonEmitter;
   
   method()
     this.commonEmitter_.emit('eventName',  data: true);
   

然后你的测试文件可能是

let commonEmitterMock: any

beforeEach(() => 
  commonEmitterMock = createMock('emit');
);


it('testMyClass', async () => 
   const method = new MyClass(commonEmitterMock).method();
   expect(commonEmitterMock).toHaveBeenCalledWith('eventName',  data: true)

【讨论】:

那个实现给了我以下错误:匹配器错误:接收到的值必须是模拟或间谍函数。收到的类型:对象 |收到的值:"emit": [Function mockConstructor]【参考方案2】:

要测试您的 http 请求事件的不同分支而不放弃过度设计的代码,您可以执行以下操作。

这是我打算使用 Jest 测试的函数的存根版本:



    function myRequest(resolve, reject) 
        http.request(url, options, (res: IncomingMessage) => 
            response.on('data', (chunk) => 
              // On data event code
            )
            response.on('end', () => 
              // On end event code
              resolve()
            )
            response.on('error', (err) => 
              reject(err)
            )
        
    

首先,我们需要模拟 http 库并覆盖请求实现以手动触发回调并注入我们模拟的响应对象:



    ...
    const mockRes = 
       write: jest.fn(),
       on: jest.fn(),
       end: jest.fn()
    
        
    jest.mock('http', () => (
       request: jest.fn().mockImplementation((url, options, cb) => 
          cb(mockRes)
       )
    )

然后,我们的每个开玩笑的测试单元,我们手动触发我们希望测试的每个事件的回调,将数据传递给每个特定的回调:



    it('should call request callback and reject for invalid content response', async () => 
        const resolve = jest.fn()
        const reject = jest.fn()
    
        mockRes.on.mockImplementation((event, cb) => 
          if (event === 'end') 
            cb()
           else if (event === 'data') 
            cb(new Error('invalid_json_string'))
          
        )
    
        // @ts-ignore
        myRequest(resolve, reject)
    
        // @ts-ignore
        expect(mockRes.on).toHaveBeenCalledWith('data', expect.any(Function))
        expect(mockRes.on).toHaveBeenCalledWith('end', expect.any(Function))
        expect(reject).toHaveBeenCalledWith(expect.any(Error))
      )

【讨论】:

以上是关于用玩笑模拟自定义事件发射器的主要内容,如果未能解决你的问题,请参考以下文章

Node.js自定义对象事件监听与发射

Angular2自定义表单控件防止发射事件

父子组件信息传递(子传父)

使用动态组件和自定义事件时的 VueJS 警告

js原生创建模拟事件和自定义事件的方法

js事件自定义dom事件自定义事件