Postman does interface automation testing - getting started

  • Probably the best web interface debugging tool currently available
  • No need to register (multi-terminal synchronization use cases can be used after registration)
  • Free ($60 per year cloud service available, 30-day free trial)
  • save history
  • Support recording requests
  • Based on Chrome's V8 engine, it supports JS scripts (basically supports ES6, except for browser-related objects and APIs, require() importetc.)
  • The same code and use cases can be used for automated interface testing, see its command-line version Newman introduction
  • Can generate HTTP request code templates in various languages
  • Can generate better-looking online API documents (support MarkDown)
  • Provide a simple version of continuous integration (Monitor function, only supports public network IP requests... not as practical as Jenkins)

Reasons for choosing it for automated testing:

  • Satisfies most scenarios of Internet companies
  • Ultra-light, compared with another popular choice - JMeter has low threshold, high development efficiency, and pleasing interface
  • The development is almost one person, easy to communicate, easy to promote development self-test
  • It is easy to pull the function test into the pit, and it is easy to hand over when there is a personnel change

Reasons not to choose it:

  • Limited functions: Postman runs in a sandbox. Although Newman is based on Node.js, a set of scripts shared by two sides determines that its functions cannot be more than Postman, and it cannot be used in the following scenarios:
    • Need to read and write files
    • Need to read and write database
    • Need to introduce external libraries, such as uncommon/custom encryption methods
    • Non-HTTP protocol
  • After all, it is a small debugging tool, and there is a clear gap with mature automated testing frameworks in terms of management use cases, code reuse, stability, reporting, and even ease of use. People who use it must have enough ability to climb out of the pit
  • If the project often uses JMeter for interface testing, and someone is familiar with JMeter, you can consider splitting the script into the granularity of a single interface, and spend some effort to automate both functions and performance, without maintaining two sets
  • If all English and lack of Chinese materials are also counted

Install

www.getpostman.com/apps

It is recommended to choose the Mac/Windows app. Compared with the Chrome app, the download does not need to bypass the wall, and the function is more powerful


basic use

official document

tutorial

Interface testing tool postman , 2016-09-01 (Chrome-based Postman, similar to the desktop version)
[API testing]postman , 2016-02-29
API automation testing tool - Postman , 2015-09-26 (in the tutorial The version is relatively old, but it is still good)
How to write powerful automated API tests with Postman, Newman and Jenkins , 2015-09-03
How to write automated tests for APIs using Postman – Part 1 , 2014-03-07
How to write automated tests for APIs with Postman – Part 2 , 2014-04-17
Writing automated tests with Postman – Part 3 , 2014-05-09

  • Some early articles will mention Jetpack, which used to charge $10, and now it has become the Collection Runner that comes with Postman, which can execute use cases in batches

example

Postman Echo

Making the perfect HTTP request using Postman Echo, 2015-11-13

Cooper's Meal Plan

Conditional Workflows in Postman, 2016-03-23

Spotify Playlist Generator

Generate Spotify Playlists using a Postman Collection, 2016-11-09

CurencyCloud's Postman Collection and Usage Instructions


recording interface

Capturing requests (native app)
Using Postman Proxy to Capture and Inspect API Calls from iOS or Android Devices,2016-06-26

When the interface caller wants to test the business logic, there is no need for Fiddler/Charles to capture packets and fill them in one by one.
Open the Postman proxy (port 5555 by default), and set the corresponding IP and port on the browser/mobile phone.

Supports regular expressions to filter URLs, and it is recommended to exclude static resources, traffic statistics stations, and websites that other background processes request from time to time
baidu|google|microsoft|github|qq\.com|.*\.(html?|css|js|png|jpe?g|webp|ico)$

You can set the saving location:
If all operation steps need to be interface tested, it is recommended to save directly to the target collection.
If only one or a few interfaces are selected from a large number of operations, it is recommended to save to the history record, pick out the desired one and save it to Target collection, no need to waste time deleting


Collection Runner

Running a collection

  • Good for running/debugging multiple use cases at once
  • It is suitable for developing self-test interface performance (for example, looping 10,000 times), at least the response time and stability are passed before handing over to others to call
  • The same operating environment as Newman, like Newman does not save environment variables by default, and can load data files like Newman, suitable for using the interface to adjust the use case and then put it on the command line for continuous integration

【pay attention】

There cannot be any dependencies between collections, between folders in the same collection, and between use cases with and without folders in the same collection

Postman/Newman is written in JS, and the minimum granularity of batch execution is folders. The
asynchronous nature of single thread determines that the execution order of folders has nothing to do with the order in which they appear.

Only the use cases in the same folder, or the use cases directly placed under the collection, are executed in the same order as they appear

Each collection measures 1 aspect, and each folder within the collection measures 1 completely independent sub-scene

also

  • At present, only level 1 folders are supported under the collection. It is not recommended to make the scene too complicated, and it is difficult to manage use cases.
  • Currently collections and folders can only be sorted alphabetically, use cases can be sorted by dragging
  • At present, the search cannot find the URL address. It is recommended to write the use case name /path/to/api 接口描述, which is convenient for viewing and searching
  • If you plan to do automation and continuous integration, it is recommended that the names of collections and folders be in English without spaces, which is convenient for command line calls

process control

It only takes effect in collection runner or Newman (in the normal interface, whichever you choose to send is the one)

/* 假设2个用例的顺序为:
用例A
用例B

如果希望执行顺序为: 用例A -> 用例B -> 用例A,又不想复制一份用例A,那么
*/

// 用例A的Tests里写
if (xxx) postman.setNextRequest('null');  // 终止执行

// 用例B的Tests里写
postman.setNextRequest('用例A');

// 【注意】如果不设终止条件,用例A执行完到用例B,用例B执行完又指向用例A,会构成死循环

// PS:postman是Postman提供的全局对象


Affirmation

Testing Sandbox built-in objects, methods, variables and available third-party libraries Introduction
Testing examples
Extracting data from responses and chaining requests , 2014-10-27

In the main interface, you can see the returned results with the naked eye, but if you don’t add assertions in the collection runner/Newman, you can’t know whether it is a success or a failure after running. Assertions are
written in Teststhe tab page, and you can refer to the documentation and the code template on the right side of the interface to get started:

tests['Status code is 200'] = responseCode.code === 200;  // 推荐用全等 ===,确保类型和值都一致
tests['Response time is less than 200ms'] = responseTime < 200;
tests['Body matches string'] = responseBody.has('xxx');  // 只要有指定关键字就行,在哪、有几个等都不管
tests['Content-Type is present'] = postman.getResponseHeader('Content-Type') || false;

// Postman的断言实际上就是往全局对象 tests 添加键值对
// 它的key会显示在报告界面上,value是可以解析为boolean的表达式
// 如果得出的值是true,在报告里显示为成功,false失败

// 【变通】用总是为真的断言来显示信息
tests[`[INFO] Request params: ${JSON.stringify(request.data)}`] = true;  // 显示所有请求参数(在自动化测试里很有用)
tests[`跑第${iteration + 1}次`] = true;  // 用在runner里循环很多次时
// 迭代次数 iteration 是Postman提供的全局变量,从0开始

// PS:request是Postman提供的全局对象
// responseCode(对象)、responseTime(数字)、responseBody(字符串)目前是Postman收到服务器返回内容才声明的变量

// 【注意】如果你在做自动化测试,目前在接口超时没返回时:
// responseCode、responseTime、responseBody都没定义,使用时会导致脚本出错,判断是否超时没返回的只能靠header
// request.data里的变量在超时时不解析,很容易让人误会请求参数传错了,建议此时不显示这行

about'use strict';

Because Postman provides a lot of global variables, if you write them, you 'use strict';will get a warning message where you use them


Extract interface return value

when returning JSON

let json = JSON.parse(responseBody);  // responseBody是包含整个返回内容的字符串
// 提取某字段的值:
let foobar = json.foo.bar[0].foobar;  // 假设结构为 {"foo": {"bar": [{"foobar": 1}, {"baz": 2}]}}

// 想用在自动化测试可以多写点:
let json;
try {
  json = JSON.parse(responseBody);
} catch (err) {
  tests['Expect response body to be valid JSON'] = false;
  tests[`Response body: ${responseBody}`] = true;
  console.error(err);
}

when returning HTML

// A. 用正则表达式匹配
let foo = responseBody.match(/foo/g);  // g 全局 i 不分大小写 m 多行
tests['blahblahblah'] = foo[0] === 'bar';
// 正则里包含变量时:
let foo = 'xxx';
let bar = responseBody.match(new RegExp(`^${foo}.*
, 'g');

// B. 用CheerioJS库:
let html = cheerio(responseBody);
let titleText = html.find('title').text();  // 取 标签里的文字
</code></pre>

<blockquote>
<p><a href="http://blog.getpostman.com/2016/08/30/jquery-replaced-by-cheeriojs-in-postman-sandbox/">jQuery replaced by CheerioJS in Postman Sandbox</a>, 2016-08-30</p>
</blockquote>

<hr>
<h3>设置环境变量</h3>
<blockquote>
<p><a href="https://www.getpostman.com/docs/environments">Setting up an environment with variables</a>  </p>
</blockquote>

<p>Postman的环境变量分为 environment 和 global 2种</p>

<p>实际上就是<code>environment</code>、<code>globals</code>这2个全局的对象(字典)里的内容<br>
它们的key作为变量名,value作为变量的值 </p>
<h4>environment</h4>
<p>满足99%的需要,平时只用它就够了,global留到后文讲</p>

<ul>
<li>作用域为整个集合</li>
<li>能创建多个environment文件,方便切换不同测试环境</li>
</ul>

<p>在地址栏、header、请求参数、外部数据文件里,用 <code>{
   
   {变量名}}</code> 获取环境变量的值<br>
如:<code>{
   
   {URL}}/path/to/api</code></p>

<p>(更常见的<code>${}</code>在JS的ES6语法里被占用了,Postman只能选这么个奇怪写法)</p>

<p>在<code>Pre-request Script</code>和<code>Tests</code>的代码里略有不同:</p>
<pre><code>/* 官方提供的方法 */
// 设置
postman.setEnvironmentVariable('variableKey', value);
// 注意:通过菜单或以上方法设置的环境变量,值会转成字符串,取的时候要转换

// 获取
let foo = postman.getEnvironmentVariable('variableKey');
// 字符串数字转数字:Number(foo)
// 字符串'true' 'false'转布尔值:Boolean(foo) 或 !!foo

// 更新
// 就是再设置一次同名的环境变量,换别的值

// 清除环境变量
postman.clearEnvironmentVariable('variableKey');
</code></pre>
<pre><code>/* 懒人版 */
// 既然知道实际上是操作 environment 对象,如果你有JS基础,可以直接:
// 添加key
environment.variableKey = 12345;  // 少打字,取出时也不用转换类型
// 获取
let foo = environment.variableKey;
// 清除
delete environment.variableKey;
// obj.foo = undefined; 的写法无效,Postman把undefined转成了字符串……

// 如果你非要跟自己过不去,用了变量名不允许的字符做key(比如有空格),只能写成 environment['variableKey']

// 只要没跟自己过不去,可以用ES6的对象解构语法一次取多个:
let {key1, key2, key3} = environment;
</code></pre>

<p>【注意】  </p>

<p>在Postman主界面运行过后,通过代码设置的环境变量会存到IndexedDB,跟在菜单里设置一样,用例跑完不消失  </p>

<p>但在collection runner或Newman跑则是默认不保存,跑完就消失,做自动化测试时要注意</p>

<hr>
<h3>动态请求参数</h3>
<p>在runner里循环发n次请求/做自动化测试时,有些接口不适合写死参数  </p>

<ol>
<li>Postman有以下内建变量,适合一次性使用:</li>
</ol>
<pre><code>{
   
   {$guid}}  // 生成GUID
{
   
   {$timestamp}}  // 当前时间戳
{
   
   {$randomInt}}  // 0-1000的随机整数
</code></pre>

<ol>
<li>参数依赖上一个请求的返回:</li>
</ol>

<p>上个请求的<code>Tests</code>里提取参数存环境变量,这个请求里用<code>{
   
   {变量名}}</code>取值</p>

<ol>
<li>参数每次都不同,但之后的断言或别的请求里可能还要用:</li>
</ol>

<p>在<code>Pre-request Script</code>里写代码处理,存为环境变量,参数里用<code>{
   
   {变量名}}</code>取值</p>

<p>例如</p>
<pre><code>const randomInt = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;  // 随机整数
const getRandomValue = list => list[randomInt(0, list.length - 1)];  // 随机选项

// 随机手机
environment.randomMobile = `18${randomInt(100000000, 999999999)}`;
// 随机设备名
environment.randomDevice = getRandomValue(['ios', 'android']);
</code></pre>

<p>Postman目前没有很方便的重用代码的手段,编辑框也不是IDE,没智能提示,尽量别整那么复杂</p>

<hr>
<h3>调试</h3>
<p><code>cmd + alt + c</code>(Windows <code>ctrl + alt + c</code>)打开Postman控制台,可以看请求和响应内容</p>

<p>用<code>console.log()</code>打印,到控制台看<br>
或<code>tests['这里拼出你想看的字符串'] = true</code>在界面/报告看断言</p>

<hr>
<h3>mock</h3>
<blockquote>
<p><a href="http://blog.getpostman.com/2016/01/26/using-a-mocking-service-to-create-postman-collections/">Using a mocking service to create Postman Collections</a>,2016-01-26</p>
</blockquote>

<hr>
<h3>global</h3>
<p><strong>不做自动化测试可以跳过这段</strong></p>

<p>跟environment几乎完全一样,在地址栏、header、请求参数、外部数据文件里也是<code>{
   
   {}}</code>调用,除了:</p>

<ul>
<li>只有1个global文件</li>
<li>菜单藏得较深,在生成的API文档里也不解析,决定了它不适合做参数化</li>
<li>environment和global同名时,优先用environment</li>
</ul>

<p>global只建议用在1种场景:<strong>定义公共函数</strong></p>

<p>先正常地写好函数,再用<a href="http://tool.lu/js/">在线压缩工具</a>压成一行<br>
在菜单里选 Bulk Edit,以每行一对 key:value 的形式编辑,变量名做key,函数做value</p>
<pre><code>assertNotTimeout:var hasResponse=postman.getResponseHeader('Content-Type')?true:false; if(!hasResponse) tests['服务端在超时前没返回任何数据,请检查相关服务、网络或反向代理设置(以下跳过其他断言)']=false;
logParams:if(hasResponse) tests[`[INFO] 请求参数(超时没返回时不解析):${JSON.stringify(request.data)}`]=true;
getResponseJson:try{if(hasResponse) var json=JSON.parse(responseBody);}catch(err){ tests['服务端没返回合法的JSON格式,请检查相关服务、网络或反向代理设置(以下跳过其他断言)']=false; tests[`[INFO] 返回:${responseBody}`]=true; console.error(err);}
assertType:var assertType=(name,value,type)=>{let isType=(type==='array')? Array.isArray(value):typeof value===type; tests[`${name}为${type}(实际值:${value})`]=isType;};
assertEqual:var assertEqual=(name,actual,expected)=>{tests[`${name}等于${expected}(实际值:${actual})`]=actual===expected;};
assertNotEqual:var assertNotEqual=(name,actual,expected)=>{tests[`${name}不等于${expected}(实际值:${actual})`]=actual!==expected;};

// 注意在这里定义变量只有 var 的作用域够大,用 let 或 const 的话eval后就销毁了
</code></pre>

<p>假设返回 <code>{"name":"张三","userType":1,"settings":[]}</code>,在<code>Tests</code>里一上来就写:</p>
<pre><code>eval(globals.assertNotTimeout);  // 判断是否超时(通过有没有Content-Type请求头),超时则断言失败
eval(globals.logParams);  // 如果不超时,显示发出的请求参数
eval(globals.getResponseJson);  // 如果不超时,解析返回的JSON对象,赋给json变量,返回值不合法则断言失败

// 下面定义了3个公共函数,免得每次断言都要写一大串:
eval(globals.assertType);
eval(globals.assertEqual);
eval(globals.assertNotEqual);

// 上面3个基本满足日常使用需要
if (json) {
  assertType('用户名', json.name, 'string');  // 在报告中显示为: '用户名为string,(实际值:张三)'
  assertType('设置', json.settings, 'array');  // JS里其实没有array类型(数组是object),这里做了处理,让报告更好懂

  assertEqual('用户类型', json.userType, 1);  // 显示为: '用户类型等于1,(实际值:1)'
  assertNotEqual('用户类型', json.userType, 2);  // 显示为: '用户类型不等于2,(实际值:1)'
}
</code></pre>

<p>在官方给出更方便的重用代码的方法前,这是除了复制粘贴外唯一的重用方法<br>
如果不做自动化测试,且断言写得很简单,不建议这么搞  </p>

<p>如果不幸跳了自动化的坑,通常一个项目会有100~200个接口要做自动化测试,要仔细比较哪种方法成本更高<br>
定义函数前要仔细考虑好,万一中途要改参数和返回值,已经写好的n份也得改……</p>

<p>建议定义的公共函数不超过个位数,并保留好没压缩的版本,不然别人没法接手</p>

<blockquote>
<p><a href="http://blog.getpostman.com/2015/09/29/writing-a-behaviour-driven-api-testing-environment-within-postman/">Writing a behaviour driven API testing environment within Postman</a></p>
</blockquote>
<pre><code>// 如果确实要在代码里设global
// 官方的:
postman.setGlobalVariable('variableKey', value);  // 同样存成字符串
let bar = postman.getGlobalVariable('variableKey');
postman.clearGlobalVariable('variableKey');
// 或者自己操作 globals 对象
</code></pre>

<hr>
<h3>数据文件</h3>
<p><strong>不做自动化测试可以跳过这段</strong></p>

<blockquote>
<p><a href="https://www.getpostman.com/docs/multiple_instances">Using data variables to run a collection multiple times</a><br>
<a href="http://blog.getpostman.com/2014/10/28/using-csv-and-json-files-in-the-postman-collection-runner/">Using CSV and JSON data files in the Postman Collection Runner</a>, 2014-10-28
<a href="http://blog.getpostman.com/2014/02/20/using-variables-inside-postman-and-collection-runner/">Using variables inside Postman and Collection Runner</a>, 2014-02-20</p>
</blockquote>

<p>在collection runner或命令行的Newman里可以加载数据文件  </p>
<pre><code>/* JSON格式 */
// 文件里有且只有1个数组,每个对象算1条用例(在Postman里的全局变量叫做data)
// key作为变量名,value作为变量的值

// 文件里依然可以用 {
   
   {}} 拿到环境变量,注意不要把自己绕进去:
// 如果是Pre-request Script里生成的环境变量,直接写进请求参数,不用经这里
[
  {"mobile": "17000000001", "pwd": "123456"},
  {"mobile": "17000000002", "pwd": "654321"},
  {"mobile": "17000000003", "pwd": ""},
  {"mobile": "{
   
   {ADMIN_MOBILE}}", "pwd": "{
   
   {ADMIN_PWD}}"}
]

// 显然,这是json文件,并不能在里面写代码(除非你蛋疼在value里写字符串然后在用例里eval)

// 用例的请求参数里依然用 {
   
   {key}} 拿到数据文件里的值,代码里则是 data.key
// 如果key跟environment/globals里的key重名,这里的 > environment > globals

/* CSV格式 */
// 第1行变量名,下面是值,每行1条用例,没有空格
// 没JSON格式的数据文件灵活
mobile,pwd
17000000001,123456
17000000002,654321
17000000003,
</code></pre>

<p>【注意】</p>

<p><strong>谨慎使用</strong>。这东西增加了调试和定位问题的复杂性,也就大大增加了维护成本<br>
而它带来的收益并不明显:</p>

<ol>
<li>针对单个接口的简单压力测试</li>
</ol>

<p>Postman不是正经的压测工具,既然选择了它就是图简单方便<br>
像JMeter那样用CSV文件做数据源的意义不大,还得另外写程序/脚本生成这样的文件,时间上不划算<br>
直接用代码生成数据就好,不差那一两毫秒</p>

<ol>
<li>数据驱动测试:一条用例测多种参数组合,包括合法和非法值,避免复制粘贴n条略有不同的</li>
</ol>

<p>很诱人,但是</p>

<ul>
<li>产品设计时有考虑异常情况吗?</li>
<li>需求来源是否统一?</li>
<li>需求是否足够稳定?</li>
<li>整个项目有统一的异常处理规范还是看开发个人习惯?</li>
</ul>

<p>如果不确定有些输入要不要/怎么处理,意味着改动可能会非常大<br>
今天非法,明天变合法,后天又变非法  </p>

<p>如果冒烟用例用在持续集成,有测试不通过会阻止发布,会严重干扰正常发版,也影响大家对自动化测试的信心</p>

<p>此外</p>

<ul>
<li>内部的基础组件为了不同项目通用,可能会允许看起来相当没道理的值</li>
<li>不对外暴露的接口为了性能,可能会有意去掉所有校验</li>
</ul>

<p>不要因为所谓“测试思维”,就在不了解的情况下为了测试而测试<br>
这种力气留到探索性测试和安全测试,自动化测试还是要讲求稳定和省事</p>

<p>此外</p>

<ul>
<li>为了能匹配正常和异常情况(和具体哪一种异常情况),断言必须写得比平时复杂</li>
<li>然后你会希望把断言条件也写进数据文件里,一种格式,eval后到处通用</li>
<li>然后数据文件的格式会变得远比上面的示例复杂</li>
<li>然后你会准备一键生成模板的脚本,批量修改的脚本,封装Newman的脚本,一个框架的雏形……别问我怎么知道的</li>
</ul>

<p>然后你回过头发现,一开始不用数据文件不就省事多了?!  </p>

<hr>
<h3>收费功能</h3>
<p>目前管理员不能解散自己创建的团队,不能删别人创建的环境变量模板,几乎残废<br>
不是太推荐交钱</p>
<h4>团队协作</h4>
<blockquote>
<p><a href="http://blog.getpostman.com/2016/10/27/new-more-useful-activity-feed-in-postman-collections/">New, More Useful Activity Feed in Postman Collections</a>, 2016-10-27<br>
<a href="http://blog.getpostman.com/2016/03/10/environment-sharing/">Announcing: Environment Sharing!</a>, 2016-03-10</p>
</blockquote>
<h4>让用户自己跑测试</h4>
<p>例如你要发布SDK,页面里可以带上跑Postman测试的按钮</p>

<blockquote>
<p><a href="http://blog.getpostman.com/2016/01/28/the-run-in-postman-button-for-improved-documentation/">Call for Partners: The Run in Postman Button for API documentation</a></p>
</blockquote>
        </article>

Guess you like

Origin blog.csdn.net/NHB456789/article/details/131108473