You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Sinon stub模拟dns lookup时无法触发对应回调问题排查

问题原因

  • 你对回调风格API的桩实现逻辑错误:dns.lookup 是回调模式的原生接口,你使用 stub().resolves() 是为Promise风格接口打桩的写法,这种方式只会返回一个成功态的Promise,根本不会执行你传入的第三个参数也就是回调函数,所以回调永远不会被触发。
  • 打桩的时机和操作对象错误:你在 beforeEach 里对 collectDns 做 __set__ 依赖注入,但你是在 it 用例内部才通过 rewire 引入的 collectDns 模块,beforeEach 里操作的 collectDns 不是你实际测试用的实例,打桩根本没有生效。
  • 没有处理异步测试的等待逻辑:collectDns 虽然标记了async,但内部没有返回Promise也没有await逻辑,你在测试里直接调用 collectDns() 后用例会直接执行结束,就算回调能触发,你也等不到执行时机。
  • 参数匹配逻辑存在问题:你调用 lookup 时传了 all: true,原生接口此时返回的地址是数组格式,你当前的fake数据是单个对象,就算回调能触发,后续逻辑也会因为数据格式不对出错。

修正方案

1. 调整业务代码(可选,建议适配async语法)

如果坚持使用回调风格,需要将逻辑包装为Promise返回,适配异步测试:

const { lookup } = require('dns');
module.exports = async function collectDns() {
    return new Promise((resolve, reject) => {
        lookup('google.com', { all: true, family: 4 }, (err, addresses) => {
            console.log(err);
            console.log(addresses);
            err ? reject(err) : resolve(addresses);
        });
    })
};

也可以直接使用Node.js内置的Promise版本dns接口,代码更简洁:

const { lookup } = require('dns').promises;
module.exports = async function collectDns() {
    try {
        const addresses = await lookup('google.com', { all: true, family: 4 });
        console.log(addresses);
        return addresses;
    } catch (err) {
        console.log(err);
        throw err;
    }
};

2. 修正单元测试代码

const { stub } = require('sinon');
const rewire = require('rewire');
const expect = require('chai').expect;

describe('collectDns 测试', () => {
    let collectDns, revert, lookupStub;
    // 先引入模块再打桩
    beforeEach('stub deps', () => {
        collectDns = rewire('../collectdns');
        const lookupFake = [{ address: '127.0.0.1', family: 4 }]; // 匹配all:true的数组返回格式
        // 回调风格接口打桩:调用时主动触发回调
        lookupStub = stub().callsFake((domain, options, callback) => {
            callback(null, lookupFake);
        });
        // 如果是使用Promise版本的lookup,上面的打桩代码替换为下面这行即可
        // lookupStub = stub().resolves(lookupFake);
        revert = collectDns.__set__({
            'lookup': lookupStub,
        });
    });

    afterEach(() => {
        revert(); // 执行恢复逻辑,避免桩污染其他用例
    });

    it('run DNS lookup', async () => {
        const res = await collectDns(); // 等待异步逻辑执行完成
        // 断言调用符合预期
        expect(lookupStub.calledOnce).to.be.true;
        expect(lookupStub.calledWith('google.com', { all: true, family: 4 })).to.be.true;
        expect(res).to.deep.equal([{ address: '127.0.0.1', family: 4 }]);
    });
})

内容的提问来源于stack exchange,提问作者Bob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 21:18:04