如何在模拟函数内编写对模拟函数的测试?我想测试我的
publish
模拟函数是否被调用一次。
jest.mock('amqplib', () => ({
connect: jest.fn(() => Promise.resolve({
createChannel: jest.fn(() => Promise.resolve({
assertExchange: jest.fn(),
publish: jest.fn(),
})),
close: jest.fn(),
})),
}));
我想测试的实际功能。
export default function (key, data, exchange = 'portal.topic', options = { type: 'topic' }) {
return amqp.connect(`amqp://${RABBITMQ_USER}:${RABBITMQ_PASS}@${RABBITMQ_URL}:${RABBITMQ_PORT}`).then(conn => {
conn.createChannel().then((ch) => {
ch.assertExchange(exchange, options.type, { durable: true });
ch.publish(exchange, key, Buffer.from(JSON.stringify(data)));
});
setTimeout(() => { conn.close(); }, 1000);
});
}
首先,我建议根据您的逻辑从代码中删除
setTimeout
,并且conn.createChannel
方法不会与外部promise形成promise链。更改后,单元测试:
index.js
:
import amqp from 'amqplib';
const RABBITMQ_USER = 'RABBITMQ_USER';
const RABBITMQ_PASS = 'RABBITMQ_PASS';
const RABBITMQ_URL = 'RABBITMQ_URL';
const RABBITMQ_PORT = 'RABBITMQ_PORT';
export default function(key, data, exchange = 'portal.topic', options = { type: 'topic' }) {
return amqp
.connect(`amqp://${RABBITMQ_USER}:${RABBITMQ_PASS}@${RABBITMQ_URL}:${RABBITMQ_PORT}`)
.then((conn) => {
return conn.createChannel().then((ch) => {
ch.assertExchange(exchange, options.type, { durable: true });
ch.publish(exchange, key, Buffer.from(JSON.stringify(data)));
return conn;
});
})
.then((conn) => conn.close());
}
index.test.js
:
import createChannel from './';
import amqp from 'amqplib';
describe('44922162', () => {
afterAll(() => {
jest.restoreAllMocks();
});
it('should create channel correctly', async () => {
const mCh = { assertExchange: jest.fn(), publish: jest.fn() };
const mConn = { createChannel: jest.fn().mockResolvedValueOnce(mCh), close: jest.fn() };
const connectSpy = jest.spyOn(amqp, 'connect').mockResolvedValueOnce(mConn);
const data = { payload: '123' };
await createChannel('key', data);
expect(connectSpy).toBeCalledWith('amqp://RABBITMQ_USER:RABBITMQ_PASS@RABBITMQ_URL:RABBITMQ_PORT');
expect(mConn.createChannel).toBeCalledTimes(1);
expect(mCh.assertExchange).toBeCalledWith('portal.topic', 'topic', { durable: true });
expect(mCh.publish).toBeCalledWith('portal.topic', 'key', Buffer.from(JSON.stringify(data)));
expect(mConn.close).toBeCalledTimes(1);
});
});
带有覆盖率报告的单元测试结果:
PASS src/stackoverflow/44922162/index.test.js (11.008s)
44922162
✓ should create channel correctly (7ms)
----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
index.js | 100 | 100 | 100 | 100 | |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 12.335s
源代码:https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/44922162
我知道这可能有点过时,因为这个问题是在 2020 年提出的,但我只是在搜索时偶然发现了这个,所以为什么不给出我自己的解决方案。
所以,我的写法有点不同,因为我不希望我的测试套件在测试时连接到真正的 RabbitMQ 服务器。
rabbitmq.wrapper.ts
export const rabbitmqWrapper = {
connect: jest.fn().mockImplementation(()=>this),
connection: {
createChannel: jest.fn().mockImplementation(()=>this),
assertExchange: jest.fn().mockImplementation((exchange: string, type: string, options: any) => {
console.log(exchange, type, options);
return this;
}),
publish: jest.fn().mockImplementation((exchange: string, routingKey: string, content: Buffer, options: any) => {
console.log(exchange, routingKey, options);
return true;
})
}
};
然后在我的测试文件中
index.test.js
import { rabbitmqWrapper } from "./rabbitmq.wrapper";
it(`Returns 201 on successful signup`, async ()=>{
{{Peform your normal test here}}
expect((await rabbitmqWrapper.connection.createChannel()).publish).toHaveBeenCalled();
}, 20000);
希望这对其他人有帮助