如何使用Mocha模拟并测试FTP连接
如何用Mocha模拟并测试FTP连接逻辑?
你现在要测试这段FTP连接的业务代码,核心是不要依赖真实的FTP服务器,而是通过模拟FTP客户端的行为来验证逻辑是否符合预期。下面我给你一步步拆解具体的实现方式:
第一步:准备测试依赖
首先得装几个必要的测试工具,在项目里执行:
npm install mocha chai sinon proxyquire --save-dev
mocha是测试框架,负责跑测试用例chai用来写断言,验证结果是否符合预期sinon用来模拟类、方法和事件,替代真实的FTP客户端proxyquire用来替换业务代码里的FTP Client依赖,让我们的模拟类生效
第二步:重构业务代码(可选但推荐)
原来的代码是直接执行的,不利于测试。建议把它抽成一个可调用的函数,方便在测试里调用:
比如新建ftp-service.js:
const Client = require('ftp'); // 假设你用的是ftp库 exports.connectAndList = () => { const client = new Client(); const connectOpts = { host: 'host', port: 21, user: 'user', password: 'password' }; client.on('ready', function() { client.list(function(err, list) { if (err) throw err; console.log(list); client.end(); }); }); client.connect(connectOpts); return client; };
第三步:编写Mocha测试用例
新建ftp-service.test.js,里面写测试逻辑:
const { expect } = require('chai'); const sinon = require('sinon'); const proxyquire = require('proxyquire'); describe('FTP连接与列表获取逻辑', () => { let mockClient; let ftpService; beforeEach(() => { // 1. 模拟FTP Client类 mockClient = sinon.spy(function() { this.on = sinon.spy(); this.connect = sinon.spy(); this.list = sinon.spy(); this.end = sinon.spy(); }); // 2. 用proxyquire替换真实的Client为我们的模拟类 ftpService = proxyquire('./ftp-service', { 'ftp': { Client: mockClient } }); }); it('应该使用正确的参数调用connect方法', () => { const expectedOpts = { host: 'host', port: 21, user: 'user', password: 'password' }; ftpService.connectAndList(); // 验证Client实例的connect方法被调用,且参数正确 const clientInstance = mockClient.returnValues[0]; expect(clientInstance.connect.calledWith(expectedOpts)).to.be.true; }); it('ready事件触发后应该调用list方法', () => { ftpService.connectAndList(); const clientInstance = mockClient.returnValues[0]; // 获取ready事件的回调函数(on方法的第二个参数) const readyCallback = clientInstance.on.getCall(0).args[1]; // 手动触发ready事件 readyCallback(); // 验证list方法被调用 expect(clientInstance.list.calledOnce).to.be.true; }); it('list成功时应该输出列表并调用end', () => { // 模拟console.log const consoleLogSpy = sinon.spy(console, 'log'); ftpService.connectAndList(); const clientInstance = mockClient.returnValues[0]; // 触发ready事件 const readyCallback = clientInstance.on.getCall(0).args[1]; readyCallback(); // 获取list方法的回调函数,手动传入成功结果 const listCallback = clientInstance.list.getCall(0).args[0]; const mockList = ['file1.txt', 'file2.jpg']; listCallback(null, mockList); // 验证console.log输出了列表,且end被调用 expect(consoleLogSpy.calledWith(mockList)).to.be.true; expect(clientInstance.end.calledOnce).to.be.true; // 恢复console.log consoleLogSpy.restore(); }); it('list出错时应该抛出错误', () => { ftpService.connectAndList(); const clientInstance = mockClient.returnValues[0]; // 触发ready事件 const readyCallback = clientInstance.on.getCall(0).args[1]; readyCallback(); // 获取list回调,传入错误 const listCallback = clientInstance.list.getCall(0).args[0]; const mockError = new Error('FTP list failed'); // 验证抛出了错误 expect(() => listCallback(mockError)).to.throw(mockError); }); });
第四步:运行测试
在package.json里加个测试脚本:
{ "scripts": { "test": "mocha ftp-service.test.js" } }
然后执行npm test就能看到测试结果了。
关键思路说明:
- 我们完全模拟了FTP Client的所有方法和事件,不需要连接真实服务器,测试速度快且稳定
- 用
sinon.spy来跟踪方法的调用情况,验证参数、调用次数是否符合预期 - 用
proxyquire替换业务代码里的真实依赖,让模拟类生效 - 通过手动触发事件和回调,控制测试流程的各个环节
内容的提问来源于stack exchange,提问作者Vitalii505
相关产品推荐
相关产品推荐

