多测师是一家拥有先进的教学理念,强大的师资团队,业内好评甚多的接口自动化测试培训机构!

17727591462

联系电话

您现在所在位置:接口自动化测试培训 > 新闻资讯

Apitest接口自动化测试工具

更新时间:2022-06-09 09:03:03 作者:多测师 浏览:44

  安装

  Apitest工具是单可执行文件,不需要安装,放到PATH路径下面就可以直接运行:

Apitest接口自动化测试工具

  # linux

  curl -L -o apitest https://github.com/sigoden/apitest/releases/latest/download/apitest-linux

  chmod +x apitest

  sudo mv apitest /usr/local/bin/

  # macos

  curl -L -o apitest https://github.com/sigoden/apitest/releases/latest/download/apitest-macos

  chmod +x apitest

  sudo mv apitest /usr/local/bin/

  # npm

  npm install -g @sigodenjs/apitest

  开始使用

  编写测试文件 httpbin.jsona

  {

  test1: {

  req: {

  url: "https://httpbin.org/anything",

  query: {

  k1: "v1",

  },

  },

  res: {

  body: { @partial

  args: {

  "k1": "v2", // 注意,这儿应该是"v1", 我们故意写"v2"以测试Apitest的反应

  },

  url: "https://httpbin.org/anything?k1=v1",

  }

  }

  }

  }

  执行如下命令测试接口。

  apitest httpbin.jsona

  其结果如下:

  main

  test1 (2.554) ?

  main.test1.res.body.args.k1: v2 ≠ v1

  {

  "req": {

  "url": "https://httpbin.org/anything",

  "query": {

  "k1": "v1"

  }

  },

  "res": {

  "headers": {

  "date": "Thu, 17 Jun 2021 15:01:51 GMT",

  "content-type": "application/json",

  "content-length": "400",

  "connection": "close",

  "server": "gunicorn/19.9.0",

  "access-control-allow-origin": "*",

  "access-control-allow-credentials": "true"

  },

  "status": 200,

  "body": {

  "args": {

  "k1": "v1"

  },

  "data": "",

  "files": {},

  "form": {},

  "headers": {

  "Accept": "application/json, text/plain, */*",

  "Host": "httpbin.org",

  "User-Agent": "axios/0.21.1",

  "X-Amzn-Trace-Id": "Root=1-60cb63df-1b8592de3767882a6e865295"

  },

  "json": null,

  "method": "GET",

  "origin": "119.123.242.225",

  "url": "https://httpbin.org/anything?k1=v1"

  }

  }

  }

  Apitest 发现了k1的值异常 main.test1.res.body.args.k1: v2 ≠ v1 并打印错误,同时还打印了接口请求响应详情。

  如果我们修改 main.test1.res.body.args.k1 值 v2 => v1 后再执行测试。

  apitest httpbin.jsona

  其结果如下:

  main

  test1 (1.889)

  Apitest 报告测试通过了。

  原理

  Apitest 执行测试文件时会加载全部测试用例,逐一执行,其执行过程可以描述为:根据 req 部分构造请求发送给服务器,收到响应后依据 res 校验响应数据,然后打印结果。

  Apitest 中的用例文件格式是 JSONA。 JSONA是JSON的超集,减轻了一些JSON语法限制(不强制要求双引号,支持注释等),再添加了一个特性:注解。上面例子中的@partial就是注解。

  为什么使用JSONA?

  接口测试的本质的就是构造并发送req数据,接收并校验res数据。数据即是主体又是核心,而JSON是最可读最通用的数据描述格式。

  接口测试还需要某些特定逻辑。比如请求中构造随机数,在响应中只校验给出的部分数据。

  JSONA = JSON + Annotation(注解)。JSON负责数据部分,注解负责逻辑部分。完美的贴合接口测试需求。

  特性

  ·跨平台

  · DSL

  - 类JSON,没有学习难度

  - 编写简单,阅读容易

  - 不要求编写者会编程

  · 数据即断言

  · 数据可访问

  · 支持Mock

  · 支持Mixin

  · 支持CI

  · 支持TDD

  · 支持用户定义函数

  · 跳过,延时,重试和循环

  · 支持Form,文件上传,GraphQL

  示例

  全等校验

  默认请求下,Apitest 进行全等校验。

  · 简单类型数据(null,boolean,string,number)完全相等

  · object数据属性和属性值完全相等,字段顺序可以不一致

  · array数据元素长度和各元素完全相等,元素顺序也要一致

  {

  test1: { @client("echo")

  req: {

  any: null,

  bool: true,

  str: "string",

  int: 3,

  float: 0.3,

  obj: {a:3, b:4},

  arr: [3,4],

  },

  res: {

  any: null,

  bool: true,

  str: "string",

  int: 3,

  float: 0.3,

  obj: {a:3, b:4},

  // obj: {b:4, b:3}, object类数据字段顺序可以不一致

  arr: [3,4],

  }

  }

  }

  Apitest 保证:只有当实际接收到的 res 数据与我们用例中描述的 res 数据全等,测试才会通过。

  数组校验技巧

  Apitest 默认全等校验,而接口返回的array数据可能几十上百条,怎么办?

  通常接口数据是结构化的,我们可以只校验数组第一个元素。

  {

  test1: { @client("echo")

  req: {

  arr: [

  {name: "v1"},

  {name: "v2"},

  {name: "v3"},

  ]

  },

  res: {

  arr: [ @partial

  {

  name: "", @type

  }

  ],

  }

  }

  }

  如果array数据的长度也很关键呢?

  {

  test1: { @client("echo")

  req: {

  arr: [

  {name: "v1"},

  {name: "v2"},

  {name: "v3"},

  ]

  },

  res: {

  arr: [ @every

  [ @partial

  {

  name: "", @type

  }

  ],

  `$.length === 3`, @eval

  ],

  }

  }

  }

  对象校验技巧

  Apitest 默认全等校验,而接口返回的object数据的属性很多,我们只关注其中部分属性?

  {

  test1: { @client("echo")

  req: {

  obj: {

  a: 3,

  b: 4,

  c: 5,

  }

  },

  res: {

  obj: { @partial

  b: 4,

  }

  }

  }

  }

  查询字符串

  通过 req.query 传入QueryString

  {

  test1: {

  req: {

  url: "https://httpbin.org/get",

  query: {

  k1: "v1",

  k2: "v2",

  }

  },

  res: {

  body: { @partial

  url: "https://httpbin.org/get?k1=v1&k2=v2",

  }

  }

  }

  }

  当然你可以把QueryString直接写在req.url中。

  {

  test1: {

  req: {

  url: "https://httpbin.org/get?k1=v1&k2=v2",

  },

  res: {

  body: { @partial

  url: "https://httpbin.org/get?k1=v1&k2=v2",

  }

  }

  }

  }

  路径变量

  通过 req.params 传入路径变量。

  {

  test1: {

  req: {

  url: "https://httpbin.org/anything/{id}",

  params: {

  id: 3,

  }

  },

  res: {

  body: { @partial

  url: "https://httpbin.org/anything/3"

  }

  }

  }

  }

  请求头/响应头

  通过 req.headers 传入请求头,通过 res.headers 校验响应头。

  {

  setCookies: { @describe("response with set-cookies header")

  req: {

  url: "https://httpbin.org/cookies/set",

  query: {

  k1: "v1",

  k2: "v2",

  },

  },

  res: {

  status: 302,

  headers: { @partial

  'set-cookie': [

  "k1=v1; Path=/",

  "k2=v2; Path=/",

  ],

  },

  body: "", @type

  }

  },

  useCookies: { @describe("request with cookie header")

  req: {

  url: "https://httpbin.org/cookies",

  headers: {

  Cookie: `setCookies.res.headers["set-cookie"]`, @eval

  }

  },

  res: {

  body: { @partial

  cookies: {

  k1: "v1",

  k2: "v2",

  }

  }

  },

  },

  }

  用例数据变量导出与引用

  凡是执行过的用例其数据均可以当做已自动导出变量,它们均可以被后续用例引用。

  Apitest 中可以使用 @eval 注解引用用例数据。

  比如上面例子中setCookies.res.headers["set-cookie"],就是引用前面setCookies用例的set-cookie响应头数据。

  表单: x-www-form-urlencoded

  {

  test1: { @describe('test form')

  req: {

  url: "https://httpbin.org/post",

  method: "post",

  headers: {

  'content-type':"application/x-www-form-urlencoded"

  },

  body: {

  v1: "bar1",

  v2: "Bar2",

  }

  },

  res: {

  status: 200,

  body: { @partial

  form: {

  v1: "bar1",

  v2: "Bar2",

  }

  }

  }

  },

  }

  表单: multipart/form-data

  结合 @file 注解实现文件上传。

  {

  test1: { @describe('test multi-part')

  req: {

  url: "https://httpbin.org/post",

  method: "post",

  headers: {

  'content-type': "multipart/form-data",

  },

  body: {

  v1: "bar1",

  v2: "httpbin.jsona", @file

  }

  },

  res: {

  status: 200,

  body: { @partial

  form: {

  v1: "bar1",

  v2: "", @type

  }

  }

  }

  }

  }

  GraphQL

  {

  test1: { @describe("test graphql")

  req: {

  url: "https://api.spacex.land/graphql/",

  body: {

  query: ``query {

  launchesPast(limit: ${othertest.req.body.count}) {

  mission_name

  launch_date_local

  launch_site {

  site_name_long

  }

  }

  }`` @eval

  }

  },

  res: {

  body: {

  data: {

  launchesPast: [ @partial

  {

  "mission_name": "", @type

  "launch_date_local": "", @type

  "launch_site": {

  "site_name_long": "", @type

  }

  }

  ]

  }

  }

  }

  }

  }

  http(s)代理

  {

  @client({

  name: "default",

  type: "http",

  options: {

  proxy: "http://localhost:8080",

  }

  })

  test1: {

  req: {

  url: "https://httpbin.org/ip",

  },

  res: {

  body: {

  origin: "", @type

  }

  }

  }

  }

  Apitest 支持通过 HTTP_PROXY HTTPS_PROXY 环境变量开全局代理。

  多个接口服务地址

  {

  @client({

  name: "api1",

  type: "http",

  options: {

  baseURL: "http://localhost:3000/api/v1",

  }

  })

  @client({

  name: "api2",

  type: "http",

  options: {

  baseURL: "http://localhost:3000/api/v2",

  }

  })

  test1: { @client("api1")

  req: {

  url: "/signup", // => http://localhost:3000/api/v1/signup

  }

  },

  test2: { @client("api2")

  req: {

  url: "/signup", // => http://localhost:3000/api/v2/signup

  }

  }

  }

  自定义超时

  你可以设置客户端超时,影响所有使用该客户端的接口。

  {

  @client({

  name: "default",

  type: "http",

  options: {

  timeout: 30000,

  }

  })

  }

  你也可以为某个用例设置超时。

  {

  test1: { @client({options:{timeout: 30000}})

  }

  }

  环境变量传递数据

  {

  test1: {

  req: {

  headers: {

  "x-key": "env.API_KEY", @eval

  }

  }

  }

  }

  mock数据

  {

  login1: {

  req: {

  url: "/signup",

  body: {

  username: 'username(3)', @mock

  password: 'string(12)', @mock

  email: `req.username + "@gmail.com"`, @eval

  }

  }

  }

  }

  Apitest 支持近40个mock函数。下面列些常用的。

  {

  test1: {

  req: {

  email: 'email', @mock

  username: 'username', @mock

  integer: 'integer(-5, 5)', @mock

  image: 'image("200x100")', @mock

  string: 'string("alpha", 5)', @mock

  date: 'date', @mock // iso8601格式的当前时间 // 2021-06-03T07:35:55Z

  date2: 'date("","2 weeks ago")', @mock // 2周前

  sentence: 'sentence', @mock

  cnsentence: 'cnsentence', @mock // 中文段落

  }

  }

  }

  用例组

  {

  @describe("这是一个模块")

  @client({name:"default",kind:"echo"})

  group1: { @group @describe("这是一个组")

  test1: { @describe("最内用例")

  req: {

  }

  },

  group2: { @group @describe("这是一个嵌套组")

  test1: { @describe("嵌套组内的用例")

  req: {

  }

  }

  }

  }

  }

  上面的测试文件打印如下:

  这是一个模块

  这是一个组

  最内用例

  这是一个嵌套组

  嵌套组内的用例

  跳过用例(组)

  {

  test1: { @client("echo")

  req: {

  },

  run: {

  skip: `othertest.res.status === 200`, @eval

  }

  }

  }

  延时执行用例(组)

  {

  test1: { @client("echo")

  req: {

  },

  run: {

  delay: 1000, // 延时毫秒

  }

  }

  }

  重试用例(组)

  {

  test1: { @client("echo")

  req: {

  },

  run: {

  retry: {

  stop:'$run.count> 2', @eval // 终止重试条件

  delay: 1000, // 重试间隔毫秒

  }

  },

  }

  }

  重复执行用例(组)

  {

  test1: { @client("echo")

  req: {

  v1:'$run.index', @eval

  v2:'$run.item', @eval

  },

  run: {

  loop: {

  delay: 1000, // 重复执行间隔毫秒

  items: [ // 重复执行数据

  'a',

  'b',

  'c',

  ]

  }

  },

  }

  }

  如果不在意数据,只想重复执行多少次的话,可以这样设置。

  {

  test1: {

  run: {

  delay: 1000,

  items: `Array(5)`, @eval

  }

  }

  }

  强制打印详情

  常规模式下,接口如果没有出错是不会打印数据详情的。通过设置run.dump为true强制打印详情数据。

  {

  test1: { @client("echo")

  req: {

  },

  run: {

  dump: true,

  }

  }

  }

  抽离公用逻辑以复用

  首先创建一个文件存储Mixin定义的文件。

  // mixin.jsona

  {

  createPost: { // 抽离路由信息到mixin

  req: {

  url: '/posts',

  method: 'post',

  },

  },

  auth1: { // 抽离鉴权到minxin

  req: {

  headers: {

  authorization: `"Bearer " + test1.res.body.token`, @eval

  }

  }

  }

  }

  @mixin("mixin") // 引入 mixin.jsona 文件

  {

  createPost1: { @describe("写文章1") @mixin(["createPost", "auth1"])

  req: {

  body: {

  title: "sentence", @mock

  }

  }

  },

  createPost2: { @describe("写文章2,带描述") @mixin(["createPost", "auth1"])

  req: {

  body: {

  title: "sentence", @mock

  description: "paragraph", @mock

  }

  }

  },

  }

  越是频繁用到的数据越适合抽离到Mixin。

  自定义函数

  某些情况下,Apitest 内置的注解不够用,你可以使用自定义函数。

  编写函数lib.js

  // 创建随机颜色

  exports.makeColor = function () {

  const letters = "0123456789ABCDEF";

  let color = "#";

  for (let i = 0; i < 6; i++) {

  color += letters[Math.floor(Math.random() * 16)];

  }

  return color;

  }

  // 判断是否是ISO8601(2021-06-02:00:00.000Z)风格的时间字符串

  exports.isDate = function (date) {

  return /^d{4}-d{2}-d{2}Td{2}:d{2}:d{2}.d{3}Z$/.test(date)

  }

  使用函数

  @jslib("lib") // 引入js文件

  {

  test1: {

  req: {

  body: {

  color: 'makeColor()', @eval // 调用 `makeColor` 函数生成随机颜色

  }

  },

  res: {

  body: {

  createdAt: 'isDate($)', @eval // $ 表示须校验字段,对应响应数据`res.body.createdAt`

  // 当然你可以直接使用regex

  updatedAt: `/^d{4}-d{2}-d{2}Td{2}:d{2}:d{2}.d{3}Z$/.test($)`, @eval

  }

  }

  }

  }

  以上内容为大家介绍了Apitest接口自动化测试工具,本文由多测师亲自撰写,希望对大家有所帮助。了解更多接口自动化测试相关知识:https://www.aichudan.com/xwzx/

联系电话

17727591462

返回顶部