安装和基本使用就不记录了,主要是在界面操作。这里记录一些脚本相关的内容。

编写测试脚本

测试脚本是通过 JavaScript 写的,编写测试脚本可以确定输出结果是否是预期结果(就不需要人工判断了)。

除了给单独的某个请求编写测试脚本,还可以给一个目录或一个测试集编写测试脚本。

编写

测试脚本可以使用动态变量,对测试结果进行断言,以及在测试结果之间传递数据。

测试脚本会在收到响应后执行,所以如果点击 Send 按钮,PostMan 会在 API 返回数据后执行你写的测试脚本。

如果需要在返回结果之前执行测试代码,可以使用 Pre-request 中的脚本。

可以使用 pm.response 对象来验证请求返回的数据。可以使用 pm.test 方法来定义测试,它可以设置测试的名称,并返回 boolean 值来确定该测试是通过还是失败。可以在断言中使用 ChaiJS BDD 语法和 pm.expect 来验证测试的细节内容。

.test 方法的第一个参数是字符串,会在测试结果里看到(也可以认为时测试的名称吧)。

举个栗子,在 Test 标签里输入下面的测试脚本,可以验证返回值是否是 200

pm.test("Status test", function () {
    pm.response.to.have.status(200);
});

点击 Send 按钮运行测试,然后打开测试结果的 Test Results 标签。这个标签的头部会显示有多少个测试通过,以及一共有多少个测试(即 (n/m) 这样的格式)。

如果这个测试返回的代码是 200,那么测试就认为它测试通过了,反之就失败。试着把代码中的期望返回值改为 400,重新执行测试,就会发现测试失败了,因为返回值是 200,而我们期望它返回 400

需要注意的是,在 pm.test 里执行的方法一旦返回 False,就会认为这个测试失败。

例如这样写,测试结果仍然时失败的:

pm.test("Status OK", function () {
    pm.response.to.have.status(200);
    pm.response.to.have.status(400);
});

除此之外,还可以测试请求的环境,比如:

pm.test("environment to be production", function () {
    pm.expect(pm.environment.get("env")).to.equal("production");
});

可以用其他的语法变量来编写测试脚本(只要是符合逻辑的就可以):

pm.test("response should be okay to process", function () {
    pm.response.to.not.be.error;
    pm.response.to.have.jsonBody("");
    pm.response.to.not.have.jsonBody("error");
});

还可以验证返回数据的格式:

pm.test("response must be valid and have a body" function () {
    pm.response.to.be.ok;
    pm.response.to.be.withBody;
    pm.response.to.be.json;
});

测试集和文件夹

上面说过了,可以给测试集、文件夹或者单独的一个请求编写测试脚本。为测试集添加一个测试脚本,可以测试 API 项目的工作流程,以覆盖到一些场景测试。

执行顺序

运行一个测试集的测试时,测试集里的所有请求都会按照我们在 PostMan 排的顺序去执行。不过,也可以通过调用 postman.setNextResquest() 来覆盖这些顺序,调用这个方法时,只需要传递请求的名称即可。

postman.setNextRequest("request_name");

使用这个方法来调用自己的话,就会循环执行当前的请求了。

停止工作流

停止工作流可以使用:

postman.setNextRequest("null");

关于 postman.setNextRequest()

  1. 指定一系列请求的名称或 ID;
  2. 它也可以用在 Pre-request 或者测试脚本里。如果有多个任务,最后一个值有优先权?
  3. 如果没有在一个请求里使用它,测试集 Runner 默认会继续执行下一个请求。

记住两点:

  • postman.setNextRequest()总是在当前请求的最后才执行,这意味着如果将这个方法放在其他代码块前面,这些代码块仍然会被执行,最后才来执行这个方法。
  • postman.setNextRequest() 是有范围的,如果是在一个文件夹里执行测试,那么它的范围就限制在文件夹里,也就是你可以跳转到这个文件夹里的任意一个请求上,但不能跳出这个文件夹。

一些测试脚本的例子

尝试写第一个测试脚本,打开 PostMan 后,输入以下 JavaScript 代码:

pm.test("Status code is 200", funciton () {
    pm.response.to.have.status(200);
});

还有另外一种写法是:

pm.test("Status code is 200", () => {
    pm.expect(pm.response.code).to.eql(200);
});

使用多个验证

可以在测试脚本里使用多个断言语句,比如:

pm.test("The response has all properties" () => {
    // parse the response json and test three properties
    const responseJson = pm.response.json();
    pm.expect(responseJson.type).to.eql('vip');
    pm.expect(responseJson.name).to.be.a('string');
    pm.expect(responseJson.id).to.have.lengthOf(1);
});

只要上面的任意一个判断失败,那么整个测试就是失败的。所有的断言都成功,测试才会通过。

解析返回数据

要对返回数据做判断,要先解析返回的数据。

JSON 数据可以使用下面的语法:

const responseJson = pm.response.json();

XML 数据可以这样转换为 JSON 格式:

const responseJson = xml2Json(pm.response.text());

CSV 数据可以用 csv 解析工具这样解析:

const parse = require('csv-parse/lib/sync');
const responseJson = parse(pm.response.text());

HTML 数据可以用 cheerio 这样解析:

const $ = cheerio.loadpm.response.text());
// output the html for testing
console.log($.html());

在不解析的情况下处理返回结果

有时候,返回的结果不是 JSON, XML, HTML, CSV 或其他可以解析的格式,也仍然可以对返回结果进行验证。

比如,可以验证一个返回的结果里是否包含某个字符串:

pm.test("Body contains string", => {
    pm.expect(pm.response.text().to.include("customer_id");
});

这时并不知道这个字符串所在的位置,因为返回数据传来的是一整个 body。可以验证返回值是否匹配某个字符串:

pm.test("Body is string", function () {
    pm.response.to.have.body("whole-body-text");
});

验证 HTTP 返回

除了验证返回的 body 之外,还可以验证返回的 status code, headers, cookies, response time 等等。

验证 body:
pm.test("Person is Jane", () => {
    const responseJson = pm.response.json();
    pm.expect(responseJson.name).to.eql("Jane");
    pm.expect(responseJson.age).to.eql(23);
});
验证 status code:
pm.test("Status code is 200", () => {
    pm.response.to.have.status(200);
});

有时候,返回其中一个 status code 即可认为测试成功,可以使用 oneOf:

pm.test("Successful POST request", () => {
    pm.expect(pm.response.code).to.be.oneOf([201, 202]);
});

也可以直接验证返回状态码的文本内容:

pm.test("Status code name has string", () => {
    pm.response.to.have.status("Created");
});
验证 header

验证返回头是否包含字段:

pm.test("Content-Type header is present", () => {
    pm.response.to.have.header("Content-Type");
});

还可以验证返回头的字段的值:

pm.test("Content-Type header is application/json", () => {
    pm.expect(pm.response.headers.get("Content-Type")).to.eql("application/json");
});
验证 cookies

验证返回中是否包含了 cookie:

pm.test("Cookie JSESSIONID is present", () => {
    pm.expect(pm.cookies.has("JSESSIONHID")).to.be.true;
});

也可以验证 cookie 的值:

pm.test("Cookie isLoggedIn has value 1", () => {
    pm.expect(pm.cookies.get("isLoggedIn")).to.eql("1");
});
验证响应时间 response time

可以验证测试的响应时间是否在一个指定的范围内:

pm.test("Response time is less than 200ms", () => {
    pm.expect(pm.response.responseTime)).to.be.below(200);
});

一些常见验证的例子

验证一个返回变量的值

可以验证返回的属性值是否与期望一致:

pm.test("Response property matches environment variable", function () {
    pm.expect(pm.response.json().name).to.eql(pm.environment.get("name"));
});
验证值的类型

可以验证返回数据中任意一部分的值的类型:

/* response has this structure:
{
    "name": "Jane",
    "age": 29,
    "hobbies": [
        "skating",
        "painting",
    ],
    "email": null
}
*/
const jsonData = pm.response.json();
pm.test("Test data type of the response", () => {
   pm.expect(jsonData).to.be.an("object");
   pm.expect(jsonData.name).to.be.a("string");
   pm.expect(jsonData.age).to.be.a("number");
   pm.expect(jsonData.hobbies).to.be.an("array");
   pm.expect(jsonData.email).to.be.null;
});
验证数组属性

可以验证数组是否为空,以及是否包含某些特定的元素:

/*
response has this structure:
{
    "errors": [],
    "areas": ["goods", "services"],
    "settings": [
        {
            "type": "visual",
            "detail": ["light", "large"]
        }
    ],
}
*/

const jsonData = pm.response.json();
pm.test("Test array properties", () => {
    // errors array is empty
    pm.expect(jsonData.errors).to.be.empty;
    // areas includes "goods"
    pm.expect(jsonData.areas).to.include("goods");
    // get the notification setting object
    const notificationSettings = jsonData.settings.find(m => m.type === "notification");
    pm.expect(notificationSettings).to.be.an("object", "Could not find the setting");
    // detail array should include "sms"
    pm.expect(notificationSettings.detail).to.include("sms");
    // detail array should include all listed
    pm.expect(notificationSettings.detail).to.have.members(["email", "sms"]);
});

.member 里的顺序不会影响测试。

验证对象属性

可以验证对象包含的 keys 和属性:

pm.expect({a: 1, b: 2}).to.have.all.keys("a", "b");
pm.expect({a: 1, b: 2}).to.have.any.keys("a", "b");
pm.expect({a: 1, b: 2}).to.not.have.any.keys("c", "d");
pm.expect({a: 1}).to.have.property("a");
pm.expect({a: 1, b: 2}).to.be.an("object").that.has.all.keys("a", "b");
  • 验证类型可以是 object, set, arraymap
  • 如果没有用 .all.any 来修饰 .keys 的话,默认是 .all
  • 由于 .keys 是基于目标类型(也就是 object)来说的,所以最好在验证 .keys 之前加上语句验证一下类型。
验证值是一个 set

可以验证返回值的有效字段:

pm.test("Value is in valid list", () => {
    pm.expect(pm.response.json().type).to.be.oneOf(["Subscriber", "Customer", "User"]);
});
验证一个对象是否被包含
/*
response has the following structure:
{
    "id": "d8893057-3e91-4cdd-a36f-a0af460b6373",
    "created": true,
    "errors": []
}
*/

pm.test("Object is contained", () => {
    const expectedObject = {
        "created": true,
        "errors": []
    }
    pm.expect(pm.response.json()).to.deep.include(expectedObject);
});

使用 .deep 会进行全部的验证,包括 .equal, .include, .members, .keys.property

验证当前环境
pm.test("Check the active environment", () => {
    pm.expect(pm.environment.name).to.eql("Production");
});

处理错误

有时会遇到一些错误或者预期之外的情况,可以使用 PostMan 的 Console 来做 debug。

例如,打印一些响应的属性值:

console.log(pm.collectionVariables.get("name"));
console.log(pm.response.json().name);

打印变量的类型:

console.log(typeof pm.response.json().id);

还可以通过 console log 来标记哪些代码被执行了,类似于跟踪:

if (pm.response.json().id) {
    console.log("id was found!");
    // do something
} else {
    console.log("no id...");
    // do something else
}
JSON not defined error

有时会遇到 ReferenceError: jsonData is not defined 的问题,一般是因为尝试去查询一个尚未声明的 JSON 对象或者要找的这个对象超出了测试代码的范围,代码编写有错。

pm.test("Test 1", () => {
    const jsonData = pm.response.json();
    pm.expect(jsonData.name).to.eql("John");
});

pm.test("Test 2", () => {
    pm.expect(jsonData.age).to.eql(29); // jsonData is not defined
});
Assertion undefined error

遇到 AssertionError: expected undefined to deeply equal.. 的报错一般是因为要验证的对象没有这个属性 (key) 。

pm.expect(jsonData.name).to.eql("John");

如果在 jsonData 里没有 name 这个 key,就会报错:AssertionError: expected undefined to deeply equal 'John'

测试未失败
验证返回值的结构

可以使用 tv4 来验证 JSON:

const schema = {
    "items": {
        "type": "boolean"
    }
}
const data1 = [true, false];
const data2 = [true, 123];

pm.test("Schema is valid", function () {
    pm.expect(tv4.validate(data1, schema)).to.be.true;
    pm.expect(tv4.validate(data2, schema)).to.be.true;
});

也可以这样:

const schema = {
    "properties": {
        "alpha": {
            "type": "boolean"
        }
    }
};
pm.test("Schema is valid", function () {
    pm.response.to.have.jsonSchema(schema);
});

发送异步请求

发送请求,然后记录返回:

pm.sendRequest("http://postman-echo.com/get", function (err, response) {
    console.log(response.json());
});

PostMan 的执行顺序

脚本也会写了一些,还要知道 Postman 的执行顺序。

在一个请求 (request) 中,执行顺序是这样的:

  1. 执行 pre-request 中的脚本;
  2. 执行 request 请求;
  3. 获得 response 返回;
  4. 执行 test 脚本。
request 执行顺序
在 request 中脚本的执行顺序

而对于每一个测试集 (collection) 里的每一个请求,脚本执行顺序是这样的:

  1. 执行测试集的 pre-request 脚本;
  2. 执行文件夹的 pre-request 脚本;
  3. 执行请求中的 pre-request 脚本;
  4. 执行 request 请求;
  5. 获得 response 返回;
  6. 执行测试集的 test 脚本;
  7. 执行文件夹的 test 脚本;
  8. 执行请求中的 test 脚本。
collection 执行顺序
在 collection 中脚本的执行顺序

文档参考: