Pact-js生成消费者契约报GET /users/login请求缺失错误排查
Pact 验证失败
Missing requests: GET /users/login 问题修复 核心问题原因
报错本质是Pact启动的本地Mock服务没有收到约定规则内的请求,由4个代码错误直接导致:
- 错误Mock了HTTP客户端:测试代码里用
jest.mock("axios")全局Mock了axios,loginUser执行时根本不会发送真实HTTP请求,Pact自然收不到任何请求。Pact消费者测试的核心逻辑是校验真实发出的请求是否符合契约约定,不需要Mock HTTP客户端。 - 请求端口不匹配:配置的Pact Mock服务监听1234端口,但
loginUser里硬编码请求地址为http://localhost:8080/users/login,就算不Mock axios,请求也会发到8080端口,无法到达Pact服务。 - 契约请求定义和实际业务逻辑不符:Pact交互规则里给GET请求定义了
body传参,但实际业务代码是把username、password放在URL查询参数(params)里传递,没有请求体,就算请求发到Pact也会匹配失败。 - 返回值逻辑不匹配:axios的GET请求返回结构中,服务端响应数据存放在
data字段下,当前loginUser直接返回整个axios响应对象,和预期的用户对象结构不一致。
修复步骤
- 移除无效的axios Mock逻辑
删除测试代码中以下内容:
- 顶部的
jest.mock("axios"); - 测试用例里的
axios.get.mockResolvedValueOnce(EXPECTED_BODY); - 所有针对axios Mock的调用次数、入参断言(这类断言属于单元测试逻辑,不属于Pact契约测试范畴)
- 改造业务代码的API地址配置,支持动态传入基础路径
不要在业务代码里硬编码服务地址,改为通过环境变量注入,默认保留原有8080端口配置,测试环境指向Pact Mock服务地址:
const API_BASE_URL = process.env.API_BASE_URL || 'http://localhost:8080'; export default async function loginUser(username, password) { try{ const res = await axios.get(`${API_BASE_URL}/users/login`, { headers: { "Content-Type": "application/json" }, params: { username: username, password: password } }) // 提取响应体数据返回,和业务预期对齐 return res.data }catch (e){ return null } }
- 调整测试生命周期逻辑,在Pact启动后注入测试环境地址
修改测试用例的beforeAll逻辑,Pact服务启动后将API基础地址指向Pact监听端口:
beforeAll(async () => { await provider.setup(); // 测试环境下所有请求发到Pact Mock服务 process.env.API_BASE_URL = `http://localhost:${provider.port}`; });
- 修正Pact交互规则的请求定义,和实际业务逻辑对齐
GET请求没有请求体,将参数定义从body移到query字段,补全匹配的请求头配置:
await provider.addInteraction({ state: 'user logged', uponReceiving: 'request logged user', withRequest: { method: 'GET', path: '/users/login', query: { username: "test", password: "11223344" }, headers: { 'Content-Type': 'application/json' } }, willRespondWith: { status: 200, headers: { 'Content-Type': 'application/json', }, body: eachLike(EXPECTED_BODY), }, });
调整完成后重新执行测试,Pact就能正常收到匹配的请求,通过校验并生成消费者契约文件。
内容的提问来源于stack exchange,提问作者yassine-eluharani
相关产品推荐
相关产品推荐

