Mock Server------用Cypress拦截接口,前端测试不卡壳
做前端测试时,经常遇到"后端接口还没好,前端没法测"的尴尬。这时候,Mock Server就成了救星------它能模拟接口返回,让前端在没有后端的情况下也能正常测试。Cypress不仅能调用接口,还能直接拦截和修改接口返回,自带"Mock功能",这一章咱们就来解锁这个技能。
一、什么是Mock?为什么需要它?
简单说,Mock就是"模拟"------当后端接口还没开发好,或者想测试异常场景(比如接口返回500错误)时,用Mock Server返回预设的结果,让前端测试能继续进行。
比如测试"登录失败"场景,不需要真的输错密码,直接Mock接口返回"密码错误"即可;测试"列表为空",直接让接口返回空数组,不用手动删数据。
二、Cypress自带的Mock:cy.intercept()
Cypress从6.0版本开始,用cy.intercept()
命令替代了旧的cy.route()
,专门用来拦截HTTP请求。它能做到:
- 监听指定接口的请求;
- 模拟接口返回(成功/失败/异常);
- 修改请求参数或返回数据。
1. 基础用法:拦截接口并返回预设数据
比如拦截"获取商品列表"接口,让它返回我们准备好的Mock数据:
javascript
it('Mock商品列表接口', () => {
// 步骤1:定义Mock数据
const mockProducts = [
{ id: 1, name: '测试商品1', price: 99 },
{ id: 2, name: '测试商品2', price: 199 }
]
// 步骤2:拦截接口,返回Mock数据
cy.intercept(
'GET', // 拦截GET请求
'/api/products', // 要拦截的接口路径
mockProducts // 预设的返回数据
).as('getProducts') // 给拦截器起个别名,方便后续等待
// 步骤3:访问页面,触发接口请求
cy.visit('/products')
// 步骤4:等待拦截的接口完成
cy.wait('@getProducts')
// 步骤5:验证页面展示正确
cy.get('[data-cy=product-item]').should('have.length', 2)
cy.get('[data-cy=product-name]').first().should('contain', '测试商品1')
})
这样一来,即使后端的/api/products
接口还没好,页面也能展示我们的Mock数据,测试能正常进行。
2. 模拟异常场景:返回错误状态码
测试接口报错时的前端表现(比如显示错误提示),可以让Mock返回500、404等状态码:
javascript
it('接口返回500时显示错误提示', () => {
// 拦截接口,返回500错误
cy.intercept(
'GET',
'/api/products',
{
statusCode: 500, // 状态码
body: { message: '服务器内部错误' } // 错误信息
}
).as('getProducts')
cy.visit('/products')
cy.wait('@getProducts')
// 验证前端显示错误提示
cy.get('[data-cy=error-message]')
.should('be.visible')
.and('contain', '服务器内部错误')
})
3. 动态修改返回数据:部分Mock
有时候不需要完全替换接口返回,只想改部分字段(比如把价格改成0测试折扣场景),可以先让请求走到真实接口,再修改返回数据:
javascript
it('修改接口返回的价格字段', () => {
// 先拦截,让请求正常发送到真实接口
cy.intercept('GET', '/api/products', (req) => {
// 等待真实接口返回后,修改数据
req.continue((res) => {
// 把所有商品价格改成0
res.body.forEach(product => {
product.price = 0
})
})
}).as('getProducts')
cy.visit('/products')
cy.wait('@getProducts')
// 验证价格都变成0
cy.get('[data-cy=product-price]').each(($el) => {
cy.wrap($el).should('contain', '0')
})
})
三、自定义Mock Server:更灵活的场景
如果需要长期维护一套Mock数据,或者多人共享,可以用json-server
搭建独立的Mock Server,配合Cypress使用:
1. 搭建本地Mock Server
-
安装
json-server
:bashnpm install -g json-server
-
创建
db.json
文件,定义Mock数据:json{ "users": [ { "id": 1, "name": "jane", "age": 20 }, { "id": 2, "name": "kevin", "age": 25 } ], "products": [ { "id": 1, "name": "手机", "price": 3000 } ] }
-
启动Mock Server:
bashjson-server --watch db.json --port 3000
访问
http://localhost:3000/users
,就能看到上面定义的用户数据了。
2. 在Cypress中调用Mock Server
测试时直接请求本地Mock Server的接口,不用依赖后端:
javascript
it('调用自定义Mock Server的接口', () => {
// 访问Mock Server的用户列表接口
cy.request('GET', 'http://localhost:3000/users')
.then((response) => {
expect(response.status).to.equal(200)
expect(response.body.length).to.equal(2)
expect(response.body[0].name).to.equal('jane')
})
// 也可以结合UI测试
cy.visit('/user-list') // 页面里的接口地址指向http://localhost:3000/users
cy.get('[data-cy=user-item]').should('have.length', 2)
})
四、Mock的最佳实践
-
区分环境 :开发环境用Mock,测试环境用真实接口,在
cypress.json
里通过环境变量控制:json{ "env": { "useMock": true, // true用Mock,false用真实接口 "mockBaseUrl": "http://localhost:3000" } }
-
Mock数据贴近真实:尽量让Mock数据的格式、字段和真实接口一致,避免后期切换时出现兼容问题。
-
清理Mock状态 :用
cy.intercept()
时,在afterEach
里重置拦截器,避免影响其他用例:javascriptafterEach(() => { cy.intercept('GET', '/api/products', (req) => { req.continue() // 让请求走真实接口 }) })