如何在Next.js集成测试中Mock第三方API(如OpenAI)调用?
解决Next.js服务端API调用OpenAI时的Playwright Mock问题
问题背景
在Next.js的API路由中调用OpenAI API时,使用nock只能拦截浏览器端发起的请求,无法Mock服务端内部的API调用——因为测试代码里的nock运行在浏览器runtime,而服务端调用属于Node环境,拦截逻辑根本触达不到。直接在API路由里硬加nock虽然能生效,但会污染生产代码,不可取。
可行解决方案
方案1:通过环境变量切换OpenAI客户端实现
创建封装层隔离真实与Mock客户端,用环境变量控制加载逻辑,完全不侵入生产代码。
- 封装OpenAI客户端
创建lib/openai.ts统一管理客户端实例:
// lib/openai.ts import { OpenAI } from 'openai'; // 定义Mock客户端,对齐真实客户端的方法签名 class MockOpenAI { chat = { completions: { create: async () => ({ choices: [ { message: { content: 'Here is your AI query answer', }, }, ], }), }, }; } // 根据环境变量初始化对应客户端 const openaiClient = process.env.NODE_ENV === 'test' ? new MockOpenAI() as unknown as OpenAI : new OpenAI({ apiKey: process.env.OPENAI_API_KEY }); export default openaiClient;
- API路由使用封装客户端
// app/api/query/route.ts import openaiClient from '@/lib/openai'; export async function GET() { const response = await openaiClient.chat.completions.create({ model: 'gpt-3.5-turbo', messages: [{ role: 'user', content: 'Test query' }], }); return Response.json({ query: response.choices[0].message.content, }); }
- 测试环境配置
在.env.test中添加NODE_ENV=test,Playwright启动时会自动加载Mock客户端。
方案2:启动测试服务时注入Nock拦截逻辑
通过自定义启动脚本,在Next.js服务启动前加载nock配置,让拦截逻辑运行在Node环境中,覆盖服务端的API请求。
- 创建Nock拦截脚本
新建mock-openai.js:
// mock-openai.js const nock = require('nock'); // 拦截OpenAI的实际接口路径(注意是POST请求) nock('https://api.openai.com') .post('/v1/chat/completions') .reply(200, { choices: [ { message: { content: 'Here is your AI query answer', }, }, ], });
- 添加测试专用启动脚本
在package.json中新增脚本:
{ "scripts": { "dev": "next dev", "test:dev": "NODE_ENV=test node -r ./mock-openai.js node_modules/.bin/next dev" } }
- 修改Playwright配置
更新playwright.config.ts中的webServer命令:
webServer: { command: 'pnpm run test:dev', url: baseURL, timeout: 120 * 1000, reuseExistingServer: !process.env.CI, },
启动测试时,nock会在Node环境中提前加载,自动拦截服务端发起的OpenAI请求。
方案3:用本地Mock服务器替代真实API
使用msw启动本地Mock服务器,拦截服务端所有指向OpenAI的请求,适合复杂Mock场景。
- 安装依赖
pnpm add msw --save-dev
- 创建Mock处理器
新建mocks/handlers.js:
// mocks/handlers.js import { rest } from 'msw'; export const handlers = [ rest.post('https://api.openai.com/v1/chat/completions', (req, res, ctx) => { return res( ctx.status(200), ctx.json({ choices: [ { message: { content: 'Here is your AI query answer', }, }, ], }) ); }), ];
- 启动Mock服务器脚本
新建start-mock-server.js:
// start-mock-server.js import { setupServer } from 'msw/node'; import { handlers } from './mocks/handlers'; const server = setupServer(...handlers); server.listen(); console.log('OpenAI Mock server running');
- 更新测试启动脚本
{ "scripts": { "test:dev": "NODE_ENV=test node start-mock-server.js & next dev" } }
方案选择建议
- 优先选方案1:逻辑清晰,完全隔离生产与测试代码,维护成本最低。
- 快速验证选方案2:无需修改业务代码,仅通过启动脚本注入Mock逻辑。
- 复杂Mock场景选方案3:支持动态返回、请求参数校验等高级功能。
内容的提问来源于stack exchange,提问作者Visrut
相关产品推荐
相关产品推荐

