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



我想断言,从 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})
}

使用此实现,永远不会调用 emit 事件。 不知道为什么,知道吗?

要在不放弃过度设计的代码的情况下测试 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)
})
})

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


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))
})

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

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})
}

最新更新