如何测试调用其他端点的Fastify接口?
解决Fastify测试中内部端点调用失败的问题
问题本质
测试时你用app.inject模拟请求,但Fastify实例并未启动真实的HTTP服务监听3000端口,所以fetch('http://localhost:3000/second')无法连接到有效服务——哪怕调试时看到secondHandler执行,也只是测试环境下的端点注册逻辑触发,而非真实网络请求被处理。另外报错“Only absolute URLs are supported”是测试环境中fetch实现(如node-fetch)在无有效服务时的异常反馈。
解决方案
方案一:模拟fetch函数(推荐,测试隔离性更好)
用Vitest的vi.mock模拟全局fetch,直接返回预期数据,无需依赖真实内部端点逻辑:
import { vi } from 'vitest' it('should respond with 200', async () => { // 模拟fetch返回成功响应 vi.spyOn(global, 'fetch').mockResolvedValue({ json: async () => ({ data: true }) }) const app = build() // 注意加await!原测试漏写导致拿不到真实响应 const response = await app.inject({ method: 'GET', url: '/first', }) expect(response.statusCode).toBe(200) expect(response.json()).toEqual({ data: { data: true } }) // 测试后清理模拟 vi.restoreAllMocks() })
方案二:用Fastify的inject代替fetch调用内部端点
修改handler代码,利用Fastify实例的inject方法直接调用内部端点,避免网络请求:
// 改用普通函数,保留this指向Fastify实例(不能用箭头函数) const handler = async function () { const secondResponse = await this.inject({ method: 'GET', url: '/second' }) const secondData = await secondResponse.json() return { data: secondData } } // 测试代码只需补全await即可 it('should respond with 200', async () => { const app = build() const response = await app.inject({ method: 'GET', url: '/first', }) expect(response.statusCode).toBe(200) })
方案三:启动真实Fastify服务器(不推荐,测试速度慢)
如果必须用真实网络请求,测试前后启停服务器:
it('should respond with 200', async () => { const app = build() // 启动服务器监听3000端口 await app.listen({ port: 3000 }) const response = await app.inject({ method: 'GET', url: '/first', }) expect(response.statusCode).toBe(200) // 测试结束关闭服务器 await app.close() })
额外注意点
- 原测试代码中
app.inject未加await,会导致response是Promise对象,直接访问statusCode必然出错,必须补加。 secondHandler里的return await { data: true }完全多余,直接return { data: true }即可,对象不是Promise,不需要await。
内容的提问来源于stack exchange,提问作者Nix
相关产品推荐
相关产品推荐

