如何测试MQTT连接建立后的EventEmitter事件订阅逻辑?
解决MQTT订阅操作的Jest测试问题
问题根源
- TypeError: Cannot read properties of undefined (reading 'on'):测试代码在MQTT客户端实例完全创建/连接建立前就尝试调用其
on方法,导致客户端对象为undefined。 - 订阅日志在测试终止后输出:未正确处理MQTT连接、订阅的异步逻辑,Jest没有等待异步操作完成就提前结束测试。
正确测试方案
1. 封装异步客户端连接函数
先写一个确保MQTT连接成功后再返回客户端实例的函数,避免操作未初始化的对象:
const mqtt = require('mqtt'); async function getConnectedClient() { const client = mqtt.connect('mqtt://localhost:1883'); return new Promise((resolve, reject) => { client.on('connect', () => resolve(client)); client.on('error', err => reject(err)); }); }
2. 编写Jest测试用例
结合async/await和Jest的done回调,处理事件驱动的异步逻辑:
describe('MQTT Subscription Tests', () => { let client; // 每个测试前完成客户端连接 beforeEach(async () => { client = await getConnectedClient(); }); // 每个测试后清理连接 afterEach(() => { client?.end(); }); test('should subscribe to target topic successfully', (done) => { const testTopic = 'test/device/data'; // 监听订阅成功事件做断言 client.on('subscribe', (granted) => { expect(granted[0].topic).toBe(testTopic); expect(granted[0].qos).toBe(0); // 按需匹配你的订阅QoS done(); // 通知Jest测试完成 }); // 执行订阅操作 client.subscribe(testTopic, { qos: 0 }); }); // 可选:测试订阅后接收消息的场景 test('should receive message on subscribed topic', (done) => { const testTopic = 'test/device/data'; const testPayload = 'test-mqtt-message'; client.subscribe(testTopic, { qos: 0 }, (err) => { if (err) return done(err); // 监听消息接收事件 client.on('message', (topic, payload) => { expect(topic).toBe(testTopic); expect(payload.toString()).toBe(testPayload); done(); }); // 发布测试消息 client.publish(testTopic, testPayload); }); }); });
3. 核心注意事项
- 所有依赖MQTT客户端的操作必须等待连接完成,用
async/await或Promise包裹初始化逻辑。 - 事件驱动的异步测试必须用
done回调,确保Jest等待事件触发后再结束测试。 - 测试后调用
client.end()清理连接,避免后续测试出现端口占用或连接冲突。
内容的提问来源于stack exchange,提问作者Erwin
相关产品推荐
相关产品推荐

