接口测试、Mock Server

本文共--字 阅读约--分钟 | 浏览: -- Last Updated: 2022-07-07

发起接口请求

在 Cypress 中发起 HTTP 请求需要用到 cy.request()

cy.request(url);
cy.request(url, body);
cy.request(method, url);
cy.request(method, url, body);
cy.request(options);

// url 为访问的接口地址,如果设置了 baseUrl,则可以略过 baseUrl
// options 是可选项,可以用来改变 cy.request() 的默认行为

cy.request({
  // 列举选项部分以及默认值
  log: true,
  url: null,
  method: 'GET',
  auth: null, // 鉴权标头
  body: null, // 随请求发送的请求体
  failOnStatusCode: null, // 返回值不是2xx或3xx时,是否直接返回失败
  form: false, // 是否将 body 的值转换为 url encoded 并设置 x-www-form-urlencoded 标头
  gzip: true, // 是否接受 gzip 编码
  headers: null, // 要发送的额外请求头
  qs: null, // 把查询参数追加到请求的 url 之后
  retryOnStatusCodeFailure: false, // statusCode 引发的失败是否自动重试,设置为true,Cypress会自动重试4次
  retryOnNetworkFailure: null, // 指网络问题引发的失败是否重试,设置为true,Cypress会自动重试4次
  timeout: responseTimeout, // 默认 timeout 时间, 可以在 cypress.json 中配置
})

发起 GET 请求

cy.request('http://www.helloqa.com');

cy.request({
  methods: 'GET',
  url: 'http://www.helloqa.com'
})

// 搭配 as
cy.request('http://www.helloqa.com').as('comments');

cy.get('@comments').should((response) => {
  expect(response).to.have.property('headers');
  expect(response).to.have.property('duration');
})

发起 POST 请求

cy.request({
  methods: 'POST',
  url: '/login',
  failOnStatusCode: false,
  form: true,
  body: {
    username,
    password
  }
}).then((res) => {
  expect(res.status).to.be.equal(200);
})

Mock Server

使用 json-server 搭建 Mock Server

1、安装

npm i -g json-server

2、创建一个 Mock 数据

// data.json
{
  "user": [
    {
      "id": 1,
      "title": "QA",
      "name": "iTesting"
    }
  ],
  "books": [
    {
      "id": 1,
      "name": "IntoCypress"
    }
  ]
}

3、启动

# 默认端口是3000
json-server --watch data.json --port 3000

4、查看资源

<!-- 访问资源 -->
http://localhost:3000/user
http://localhost:3000/books

<!-- 访问服务首页 -->
http://localhost:3000

json-server 提供的是一个 REST API 的 Mock Server,因此可以使用 POST、DELETE、GET、PUT 来测试增删查改。

使用 Mock Server 进行测试

1、配置 cypress.json

{
  "baseUrl": "http://localhost:3000"
}

2、配置 package.json

{
  "scripts": {
    "mock": "cypress open"
  }
}

3、这样编写测试文件

describe('测试 Mock Server', () => {
  it('测试 GET', () => {
    // 获取id=1的user
    // 还可以这样 /user?q=iTest, 指模糊查询包含 iTest 字样的列表项
    cy.request('/user?id=1')
      .its('headers')
      .its('content-type')
      .should('include', 'application/json')
  })

  const item = {
    "id": 2,
    "title": "kevin",
    "name": "kevin"
  }

  it('测试POST, 新增一个用户', () => {
    cy.request({
      methods: 'POST',
      url: '/user',
      headers: {'Content-Type': 'application/json'},
      body: item
    })


    // 检查是否新增成功
    cy.request('/user/').then(res => {
      expect(res.status).to.be.equal(200);
      expect(res.body.length).to.be.equal(2);
    })
  })

  const item2 = {
    "title": "jack",
    "name": "jack"
  }

  it('测试PUT, 更新一个用户', () => {
    cy.request({
      methods: 'PUT',
      url: '/user/2' // 指定更新id为2的 user
      headers: {'Content-Type': 'application/json'},
      body: item
    })

    // 检查是否更新成功
    cy.request('/user/2').then(res => {
      expect(res.status).to.be.equal(200);
      expect(res.body.title).to.be.equal(item2.title);
      expect(res.body.name).to.be.equal(item2.name);
    })
  })

  it('测试DELETE', () => {
    cy.request({
      methods: 'DELETE',
      url: '/user/2'
      headers: {'Content-Type': 'application/json'},
    })

    cy.request('/user').then(res => {
      expect(res.status).to.be.equal(200);
      expect(res.body.length).to.be.equal(1);
    })
  })
})

Cypress 自带 Mock

cy.server()

启动服务器以开始将响应路由到 cy.route() 和 cy.request()。

cy.server();
cy.server(options)

相关 options 及更多详情 请查看 这里

cy.route()

cy.server() 通常和 cy.route() 配合使用,cy.route() 语法用来管理跟控制网络请求。

cy.route(url);
cy.route(url, response);
cy.route(methods, url);
cy.route(methods, url, response);
cy.route(callbackFn);
cy.route(options);

相关 options 及更多详情 请查看 这里

其中 url 代表要请求的地址,遵循 minimatch 模式。

// 例如
cy.route('**/users/*')

// 将匹配
// /users/1
// http://helloqa.con/users/2
// https://google.con/users/3

cy.route('**/users/**')

// 将匹配
// http://helloqa.con/users/edit/2
// https://google.con/users/edit/3

使用:截获接口返回值

GET 请求举例如下:

cy.server() // 启动服务
// 监听 /users 请求的返回值,并设置别名
cy.route('**/users').as('getUsers');

// 触发请求
cy.visit('/users');

// 等待别名代表的资源解析,再执行断言
cy.wait('@getUsers').then((xhr) => {
  expect(xhr.status).to.eq(200)
})

POST 请求举例如下:

cy.server()
cy.route('POST', '**/users').as('postUser');
cy.route('GET', '**/users/details').as('getUsers');
cy.visit('/users')

// 假设 #view-details 元素上单击会触发这两个接口请求,先新增然后再次获取
cy.get('#view-details').click();
// 等待两个接口都返回
cy.wait(['@postUser', '@getUsers'])

更改接口返回值

describe('测试', () => {
  const username = 'jane.lane';
  const password = 'password123';

  it('mock 503 错误', () => {
    cy.server();
    // 监听
    cy.route({
      method: 'POST',
      url: '/login',
      status: 503,
      response: {
        success: false,
        data: 'Not success'
      }
    }).as('login');

    cy.visit('/login');
    cy.login(username, password);
    cy.get('@login').then(res => {
      expect(res.status).to.equal(503);
      expect(res.responseBody.data).to.equal('Not success');
    })
  })
})