我正在使用node 12
和Jest进行单元测试。我有一个代码可以通过websocket打开连接。
const ws = require('ws');
this.ws = new WebSocket(url);
this.ws.on('open', () => {
// How to test this callback?
...
resolve();
});
this.ws.on('error', (err) => {
// How to test this callback?
...
reject(err)
});
在我的测试案例中,我通过jtest模拟了ws
模块:
const WebSocket = require('ws');
jest.mock('ws')
test('quote server listener should be able to connect to quote server', () => {
const server = new QuoteServerListener(null, 'http://mock.com');
server.connect();
const mockWSInstance = WebSocket.mock.instances[0];
expect(mockWSInstance.on).toHaveBeenCalledTimes(1);
});
上述测试用例可以正常工作。但是我不知道如何在ws.on('open', () => ...
上触发对回调函数的调用。连接打开时,我想测试逻辑。我如何在模拟中实现这一目标?
我试图通过open
之类的mockWSInstance
实例发出一个mockWSInstance.emit('open', null)
事件,但是它不会触发代码。在这种情况下我该怎么办?
答案 0 :(得分:1)
这是单元测试解决方案:
index.ts
:
export class SomeClass {
ws;
run() {
const WebSocket = require("ws");
const url = "";
this.ws = new WebSocket(url);
return new Promise((resolve, reject) => {
this.ws.on("open", () => {
resolve();
});
this.ws.on("error", err => {
reject(err);
});
});
}
}
index.spec.ts
:
import { SomeClass } from "./";
const WebSocket = require("ws");
jest.mock("ws", () => {
const mWebSocket = {
on: jest.fn()
};
return jest.fn(() => mWebSocket);
});
describe("SomeClass", () => {
let instance;
let ws;
beforeEach(() => {
ws = new WebSocket();
instance = new SomeClass();
});
afterAll(() => {
jest.resetAllMocks();
});
it("should pass", async () => {
const eventHandler = {};
ws.on.mockImplementation((event, handler) => {
eventHandler[event] = handler;
});
const pending = instance.run();
eventHandler["open"]();
const actual = await pending;
expect(actual).toBeUndefined();
expect(ws.on).toBeCalledWith("open", eventHandler["open"]);
});
it("should fail", async () => {
const eventHandler = {};
ws.on.mockImplementation((event, handler) => {
eventHandler[event] = handler;
});
const pending = instance.run();
const mError = new Error("connection error");
eventHandler["error"](mError);
await expect(pending).rejects.toThrowError(mError);
expect(ws.on).toBeCalledWith("error", eventHandler["error"]);
});
});
覆盖率100%的单元测试结果:
PASS src/stackoverflow/59084313/index.spec.ts
SomeClass
✓ should pass (4ms)
✓ should fail (3ms)
----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
index.ts | 100 | 100 | 100 | 100 | |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 3.781s, estimated 8s
源代码:https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/59084313