Postman 详细使用指南

208 阅读9分钟

目录

  1. Postman基础介绍
  2. 界面布局和基本操作
  3. 请求管理
  4. 认证和授权
  5. 环境变量和全局变量
  6. Collection管理
  7. 脚本编写
  8. 测试和断言
  9. 数据驱动测试
  10. 团队协作
  11. 高级功能
  12. 实战案例

1. Postman基础介绍

什么是Postman?

Postman是一个功能强大的API开发和测试工具,支持:

  • API请求测试
  • 自动化测试
  • API文档生成
  • 团队协作
  • 监控和模拟

主要功能特性

🚀 核心功能:
├── HTTP请求测试 (GET, POST, PUT, DELETE等)
├── 认证支持 (OAuth, JWT, API Key等)
├── 环境管理 (开发、测试、生产环境)
├── 集合管理 (组织相关API请求)
├── 自动化测试 (脚本和断言)
├── 数据驱动测试 (CSV, JSON数据文件)
├── 团队协作 (共享集合和环境)
└── API文档生成 (自动生成和发布)

2. 界面布局和基本操作

主界面布局

┌─────────────────────────────────────────────────────────┐
│ 菜单栏 (File, Edit, View, Help)                         │
├─────────────────────────────────────────────────────────┤
│ 工具栏 (New, Import, Runner, Environments)              │
├─────────────────────────────────────────────────────────┤
│ 侧边栏                     │ 主工作区                    │
│ ├── Collections           │ ├── Request Builder         │
│ ├── Environments          │ ├── Response Viewer         │
│ ├── History               │ ├── Pre-request Script      │
│ ├── APIs                  │ └── Tests                   │
│ └── Mock Servers          │                             │
├─────────────────────────────────────────────────────────┤
│ 底部状态栏 (同步状态, 网络状态)                           │
└─────────────────────────────────────────────────────────┘

创建第一个请求

1. 点击 "New" 按钮
2. 选择 "Request"
3. 填写请求名称和描述
4. 选择或创建Collection
5. 配置请求参数
6. 点击 "Send" 发送请求

3. 请求管理

HTTP方法支持

GET     - 获取数据
POST    - 创建数据  
PUT     - 更新数据
DELETE  - 删除数据
PATCH   - 部分更新
HEAD    - 获取响应头
OPTIONS - 获取支持的方法

请求配置详解

基本URL配置

https://api.example.com/v1/users?page=1&limit=10

组成部分:
├── Protocol: https://
├── Host: api.example.com
├── Path: /v1/users
└── Query Parameters: ?page=1&limit=10

Headers配置

常用Headers:
Content-Type: application/json
Authorization: Bearer <token>
Accept: application/json
User-Agent: Postman/1.0
X-API-Key: your-api-key

请求体(Body)类型

1. JSON格式

{
  "name": "张三",
  "email": "zhangsan@example.com",
  "age": 25,
  "skills": ["Python", "JavaScript", "SQL"]
}

2. Form Data

key1: value1
key2: value2
file: [选择文件]

3. x-www-form-urlencoded

username=admin&password=123456&remember=true

4. Raw Text

Plain text content
XML content
HTML content

5. Binary

用于上传文件,如图片、PDF等

Query Parameters详解

手动添加:
Key: page     Value: 1
Key: limit    Value: 10
Key: sort     Value: created_at
Key: order    Value: desc

批量添加:
page=1&limit=10&sort=created_at&order=desc

4. 认证和授权

认证类型详解

1. No Auth

适用场景:公开API,无需认证
配置:选择 "No Auth" 即可

2. API Key

// Header方式
Key: X-API-Key
Value: your-api-key-here
Add to: Header

// Query Parameter方式  
Key: api_key
Value: your-api-key-here
Add to: Query Params

3. Bearer Token

// 配置
Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

// 自动添加到Header
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

4. Basic Auth

// 配置
Username: admin
Password: password123

// 自动编码为Base64并添加到Header
Authorization: Basic YWRtaW46cGFzc3dvcmQxMjM=

5. OAuth 2.0详细配置

// OAuth 2.0配置示例
Grant Type: Authorization Code
Callback URL: https://www.postman.com/oauth2/callback
Auth URL: https://accounts.google.com/o/oauth2/auth
Access Token URL: https://accounts.google.com/o/oauth2/token
Client ID: your-client-id
Client Secret: your-client-secret
Scope: read write
State: random-state-string

// 获取Token后自动设置
Access Token: ya29.GltHBGhQj4...
Token Type: Bearer
Expires In: 3600

6. JWT(JSON Web Token)

// Pre-request Script生成JWT
const header = {
  "alg": "HS256",
  "typ": "JWT"
};

const payload = {
  "sub": "1234567890",
  "name": "John Doe",
  "iat": Math.floor(Date.now() / 1000)
};

const secret = "your-secret-key";

// 使用crypto-js库生成JWT
const CryptoJS = require('crypto-js');

function base64UrlEscape(str) {
    return str.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
}

function base64UrlEncode(str) {
    return base64UrlEscape(CryptoJS.enc.Base64.stringify(str));
}

const encodedHeader = base64UrlEncode(CryptoJS.enc.Utf8.parse(JSON.stringify(header)));
const encodedPayload = base64UrlEncode(CryptoJS.enc.Utf8.parse(JSON.stringify(payload)));

const signature = base64UrlEscape(CryptoJS.HmacSHA256(encodedHeader + "." + encodedPayload, secret).toString(CryptoJS.enc.Base64));

const jwt = encodedHeader + "." + encodedPayload + "." + signature;

pm.environment.set("jwt_token", jwt);

5. 环境变量和全局变量

变量类型和优先级

优先级(高到低):
1. Local Variables (局部变量)
2. Data Variables (数据变量)  
3. Environment Variables (环境变量)
4. Collection Variables (集合变量)
5. Global Variables (全局变量)

环境管理实践

创建环境

// 开发环境
{
  "name": "Development",
  "values": [
    {"key": "base_url", "value": "http://localhost:8000", "enabled": true},
    {"key": "api_key", "value": "dev_api_key_123", "enabled": true},
    {"key": "db_host", "value": "localhost", "enabled": true}
  ]
}

// 测试环境  
{
  "name": "Testing",
  "values": [
    {"key": "base_url", "value": "https://api-test.example.com", "enabled": true},
    {"key": "api_key", "value": "test_api_key_456", "enabled": true},
    {"key": "db_host", "value": "test-db.example.com", "enabled": true}
  ]
}

// 生产环境
{
  "name": "Production", 
  "values": [
    {"key": "base_url", "value": "https://api.example.com", "enabled": true},
    {"key": "api_key", "value": "prod_api_key_789", "enabled": true},
    {"key": "db_host", "value": "prod-db.example.com", "enabled": true}
  ]
}

变量使用方法

// 在URL中使用
{{base_url}}/api/v1/users

// 在Headers中使用
X-API-Key: {{api_key}}

// 在请求体中使用
{
  "database_host": "{{db_host}}",
  "environment": "{{env_name}}"
}

// 在脚本中使用
const baseUrl = pm.environment.get("base_url");
const apiKey = pm.environment.get("api_key");

// 设置变量
pm.environment.set("access_token", responseJson.token);
pm.globals.set("user_id", responseJson.user.id);

动态变量

// Postman内置动态变量
{{$guid}}           // 生成GUID
{{$timestamp}}      // 当前时间戳  
{{$randomInt}}      // 随机整数
{{$randomEmail}}    // 随机邮箱
{{$randomFirstName}} // 随机名字
{{$randomLastName}}  // 随机姓氏
{{$randomPhoneNumber}} // 随机电话
{{$randomCity}}     // 随机城市

// 使用示例
{
  "id": "{{$guid}}",
  "email": "{{$randomEmail}}",
  "created_at": "{{$timestamp}}",
  "phone": "{{$randomPhoneNumber}}"
}

6. Collection管理

Collection结构

My API Collection/
├── Authentication/
│   ├── Login
│   ├── Refresh Token
│   └── Logout
├── Users/
│   ├── Get All Users
│   ├── Get User by ID
│   ├── Create User
│   ├── Update User
│   └── Delete User
├── Posts/
│   ├── Get All Posts
│   ├── Create Post
│   └── Delete Post
└── Utilities/
    ├── Health Check
    └── Get Server Info

Collection级别配置

Pre-request Script(集合级别)

// 为整个Collection设置通用认证
const authUrl = pm.environment.get("auth_url");
const username = pm.environment.get("username");
const password = pm.environment.get("password");

// 检查token是否过期
const tokenExpiry = pm.environment.get("token_expiry");
const currentTime = new Date().getTime();

if (!tokenExpiry || currentTime > tokenExpiry) {
    // Token过期,重新获取
    pm.sendRequest({
        url: authUrl + "/login",
        method: 'POST',
        header: {
            'Content-Type': 'application/json'
        },
        body: {
            mode: 'raw',
            raw: JSON.stringify({
                username: username,
                password: password
            })
        }
    }, function (err, response) {
        if (err) {
            console.error("认证失败:", err);
            return;
        }
        
        const responseJson = response.json();
        const token = responseJson.access_token;
        const expiresIn = responseJson.expires_in * 1000; // 转换为毫秒
        const expiryTime = new Date().getTime() + expiresIn;
        
        pm.environment.set("access_token", token);
        pm.environment.set("token_expiry", expiryTime);
        
        console.log("Token刷新成功");
    });
}

Tests(集合级别)

// 通用响应验证
pm.test("响应时间小于2秒", function () {
    pm.expect(pm.response.responseTime).to.be.below(2000);
});

pm.test("响应状态码正确", function () {
    pm.expect(pm.response.code).to.be.oneOf([200, 201, 204]);
});

pm.test("响应包含必要的Headers", function () {
    pm.expect(pm.response.headers.has("Content-Type")).to.be.true;
    pm.expect(pm.response.headers.has("Date")).to.be.true;
});

// 通用错误处理
if (pm.response.code >= 400) {
    console.error("请求失败:", pm.response.status);
    console.error("错误详情:", pm.response.text());
}

Collection导入导出

// 导出Collection
1. 右键点击Collection
2. 选择 "Export"
3. 选择版本 (推荐v2.1)
4. 保存为JSON文件

// 导入Collection
1. 点击 "Import" 按钮
2. 选择文件或拖拽文件
3. 确认导入设置
4. 点击 "Import"

// 分享Collection
1. 右键点击Collection
2. 选择 "Share"
3. 设置权限 (View/Edit)
4. 生成分享链接

7. 脚本编写

Pre-request Scripts详解

基础脚本示例

// 设置请求头
pm.request.headers.add({
    key: 'X-Request-ID',
    value: pm.variables.replaceIn('{{$guid}}')
});

// 动态设置URL参数
pm.request.url.query.add({
    key: 'timestamp',
    value: new Date().getTime().toString()
});

// 修改请求体
if (pm.request.body && pm.request.body.mode === 'raw') {
    let requestBody = JSON.parse(pm.request.body.raw);
    requestBody.timestamp = new Date().toISOString();
    pm.request.body.raw = JSON.stringify(requestBody);
}

高级认证脚本

// OAuth 2.0 Token刷新
function refreshOAuthToken() {
    const refreshToken = pm.environment.get("refresh_token");
    const tokenUrl = pm.environment.get("token_url");
    const clientId = pm.environment.get("client_id");
    const clientSecret = pm.environment.get("client_secret");
    
    if (!refreshToken) {
        console.error("Refresh token不存在");
        return;
    }
    
    pm.sendRequest({
        url: tokenUrl,
        method: 'POST',
        header: {
            'Content-Type': 'application/x-www-form-urlencoded'
        },
        body: {
            mode: 'urlencoded',
            urlencoded: [
                {key: 'grant_type', value: 'refresh_token'},
                {key: 'refresh_token', value: refreshToken},
                {key: 'client_id', value: clientId},
                {key: 'client_secret', value: clientSecret}
            ]
        }
    }, function (err, response) {
        if (err) {
            console.error("Token刷新失败:", err);
            return;
        }
        
        const responseJson = response.json();
        pm.environment.set("access_token", responseJson.access_token);
        pm.environment.set("refresh_token", responseJson.refresh_token);
        
        console.log("Token刷新成功");
    });
}

// 检查并刷新token
const token = pm.environment.get("access_token");
const tokenExpiry = pm.environment.get("token_expiry");
const currentTime = new Date().getTime();

if (!token || (tokenExpiry && currentTime > tokenExpiry)) {
    refreshOAuthToken();
}

Tests脚本详解

基础测试断言

// 状态码测试
pm.test("状态码是200", function () {
    pm.response.to.have.status(200);
});

// 响应时间测试
pm.test("响应时间小于500ms", function () {
    pm.expect(pm.response.responseTime).to.be.below(500);
});

// 响应头测试
pm.test("Content-Type是JSON", function () {
    pm.expect(pm.response.headers.get("Content-Type")).to.include("application/json");
});

// 响应体测试
pm.test("响应包含用户数据", function () {
    const responseJson = pm.response.json();
    pm.expect(responseJson).to.have.property('users');
    pm.expect(responseJson.users).to.be.an('array');
    pm.expect(responseJson.users.length).to.be.above(0);
});

高级测试脚本

// JSON Schema验证
const schema = {
    "type": "object",
    "properties": {
        "id": {"type": "integer"},
        "name": {"type": "string"},
        "email": {"type": "string", "format": "email"},
        "created_at": {"type": "string", "format": "date-time"}
    },
    "required": ["id", "name", "email"]
};

pm.test("响应符合JSON Schema", function () {
    const responseJson = pm.response.json();
    pm.expect(tv4.validate(responseJson, schema)).to.be.true;
});

// 数据一致性测试
pm.test("用户数据一致性检查", function () {
    const responseJson = pm.response.json();
    const user = responseJson.user;
    
    // 检查邮箱格式
    pm.expect(user.email).to.match(/^[^\s@]+@[^\s@]+\.[^\s@]+$/);
    
    // 检查年龄范围
    pm.expect(user.age).to.be.within(0, 150);
    
    // 检查状态值
    pm.expect(user.status).to.be.oneOf(['active', 'inactive', 'pending']);
    
    // 检查时间戳
    const createdAt = new Date(user.created_at);
    const now = new Date();
    pm.expect(createdAt).to.be.below(now);
});

// 业务逻辑测试
pm.test("业务规则验证", function () {
    const responseJson = pm.response.json();
    
    // VIP用户应该有特殊权限
    if (responseJson.user.is_vip) {
        pm.expect(responseJson.user.permissions).to.include('premium_features');
    }
    
    // 管理员应该有管理权限
    if (responseJson.user.role === 'admin') {
        pm.expect(responseJson.user.permissions).to.include('user_management');
    }
});

// 保存响应数据到变量
pm.test("保存响应数据", function () {
    const responseJson = pm.response.json();
    
    if (responseJson.user) {
        pm.environment.set("user_id", responseJson.user.id);
        pm.environment.set("user_token", responseJson.user.token);
    }
    
    if (responseJson.pagination) {
        pm.environment.set("next_page", responseJson.pagination.next_page);
        pm.environment.set("total_pages", responseJson.pagination.total_pages);
    }
});

8. 测试和断言

Chai断言库

// 基本断言
pm.expect(actual).to.equal(expected);           // 严格相等
pm.expect(actual).to.eql(expected);             // 深度相等
pm.expect(actual).to.not.equal(unexpected);    // 不相等
pm.expect(actual).to.be.true;                  // 布尔值true
pm.expect(actual).to.be.false;                 // 布尔值false
pm.expect(actual).to.exist;                    // 存在且不为null/undefined

// 类型断言
pm.expect(actual).to.be.a('string');           // 字符串类型
pm.expect(actual).to.be.an('array');           // 数组类型
pm.expect(actual).to.be.an('object');          // 对象类型
pm.expect(actual).to.be.a('number');           // 数字类型
pm.expect(actual).to.be.a('boolean');          // 布尔类型

// 数值断言
pm.expect(actual).to.be.above(5);              // 大于5
pm.expect(actual).to.be.below(10);             // 小于10
pm.expect(actual).to.be.within(5, 10);         // 在5-10之间
pm.expect(actual).to.be.closeTo(10.5, 0.5);    // 接近10.5,误差0.5

// 字符串断言
pm.expect(actual).to.include('substring');      // 包含子字符串
pm.expect(actual).to.match(/pattern/);          // 匹配正则表达式
pm.expect(actual).to.have.lengthOf(5);          // 长度为5

// 数组/对象断言
pm.expect(actual).to.have.property('key');      // 有属性key
pm.expect(actual).to.have.property('key', 'value'); // 属性key的值为value
pm.expect(actual).to.have.all.keys('a', 'b');   // 只有a、b两个键
pm.expect(actual).to.include.keys('a', 'b');    // 包含a、b键
pm.expect(actual).to.have.lengthOf(3);          // 数组长度为3
pm.expect(actual).to.include(item);             // 数组包含item

响应断言实例

// 完整的API响应测试套件
pm.test("API响应完整性测试", function () {
    const responseJson = pm.response.json();
    
    // 1. 基础响应检查
    pm.expect(pm.response.code).to.equal(200);
    pm.expect(pm.response.responseTime).to.be.below(1000);
    
    // 2. 响应结构检查
    pm.expect(responseJson).to.have.property('data');
    pm.expect(responseJson).to.have.property('message');
    pm.expect(responseJson).to.have.property('status');
    
    // 3. 数据类型检查
    pm.expect(responseJson.data).to.be.an('array');
    pm.expect(responseJson.message).to.be.a('string');
    pm.expect(responseJson.status).to.be.a('number');
    
    // 4. 数据内容检查
    pm.expect(responseJson.status).to.equal(1);
    pm.expect(responseJson.message).to.include('success');
    
    // 5. 数组数据检查
    if (responseJson.data.length > 0) {
        const firstItem = responseJson.data[0];
        pm.expect(firstItem).to.have.property('id');
        pm.expect(firstItem).to.have.property('name');
        pm.expect(firstItem.id).to.be.a('number');
        pm.expect(firstItem.name).to.be.a('string');
    }
});

// 分页数据测试
pm.test("分页数据测试", function () {
    const responseJson = pm.response.json();
    
    if (responseJson.pagination) {
        const pagination = responseJson.pagination;
        
        // 分页字段存在性检查
        pm.expect(pagination).to.have.all.keys(
            'current_page', 'total_pages', 'per_page', 'total_count'
        );
        
        // 分页数据合理性检查
        pm.expect(pagination.current_page).to.be.within(1, pagination.total_pages);
        pm.expect(pagination.per_page).to.be.above(0);
        pm.expect(pagination.total_count).to.be.at.least(0);
        
        // 数据一致性检查
        const expectedMaxItems = pagination.per_page;
        const actualItems = responseJson.data.length;
        
        if (pagination.current_page < pagination.total_pages) {
            pm.expect(actualItems).to.equal(expectedMaxItems);
        } else {
            pm.expect(actualItems).to.be.at.most(expectedMaxItems);
        }
    }
});

错误处理测试

// 错误响应测试
pm.test("错误处理测试", function () {
    if (pm.response.code >= 400) {
        const responseJson = pm.response.json();
        
        // 错误响应应该包含错误信息
        pm.expect(responseJson).to.have.property('error');
        pm.expect(responseJson.error).to.have.property('code');
        pm.expect(responseJson.error).to.have.property('message');
        
        // 错误代码应该是字符串或数字
        pm.expect(responseJson.error.code).to.satisfy(function (code) {
            return typeof code === 'string' || typeof code === 'number';
        });
        
        // 错误消息应该是非空字符串
        pm.expect(responseJson.error.message).to.be.a('string');
        pm.expect(responseJson.error.message.length).to.be.above(0);
        
        console.log("错误信息:", responseJson.error.message);
    }
});

// 状态码分类测试
pm.test("HTTP状态码分类测试", function () {
    const statusCode = pm.response.code;
    
    switch (Math.floor(statusCode / 100)) {
        case 2: // 2xx 成功
            pm.expect(pm.response.json()).to.have.property('data');
            break;
        case 4: // 4xx 客户端错误
            pm.expect(pm.response.json()).to.have.property('error');
            console.log("客户端错误:", pm.response.status);
            break;
        case 5: // 5xx 服务器错误
            pm.expect(pm.response.json()).to.have.property('error');
            console.error("服务器错误:", pm.response.status);
            break;
        default:
            pm.expect.fail("未预期的状态码: " + statusCode);
    }
});

9. 数据驱动测试

CSV数据文件

username,password,expected_status,expected_message
admin,password123,200,Login successful
user1,wrongpass,401,Invalid credentials
user2,password456,200,Login successful
,password123,400,Username required
admin,,400,Password required

JSON数据文件

[
  {
    "username": "admin",
    "password": "password123",
    "expected_status": 200,
    "expected_message": "Login successful"
  },
  {
    "username": "user1", 
    "password": "wrongpass",
    "expected_status": 401,
    "expected_message": "Invalid credentials"
  },
  {
    "username": "user2",
    "password": "password456", 
    "expected_status": 200,
    "expected_message": "Login successful"
  }
]

数据驱动测试脚本

// 在请求中使用数据变量
// URL: {{base_url}}/login
// Body:
{
  "username": "{{username}}",
  "password": "{{password}}"
}

// Tests脚本中使用数据验证
pm.test("登录测试 - " + pm.iterationData.get("username"), function () {
    const expectedStatus = parseInt(pm.iterationData.get("expected_status"));
    const expectedMessage = pm.iterationData.get("expected_message");
    
    pm.expect(pm.response.code).to.equal(expectedStatus);
    
    const responseJson = pm.response.json();
    pm.expect(responseJson.message).to.include(expectedMessage);
    
    // 记录测试结果
    console.log(`用户: ${pm.iterationData.get("username")}, 状态: ${pm.response.code}, 消息: ${responseJson.message}`);
});

// 条件测试
pm.test("成功登录后应返回token", function () {
    const expectedStatus = parseInt(pm.iterationData.get("expected_status"));
    
    if (expectedStatus === 200) {
        const responseJson = pm.response.json();
        pm.expect(responseJson).to.have.property('token');
        pm.expect(responseJson.token).to.be.a('string');
        pm.expect(responseJson.token.length).to.be.above(0);
        
        // 保存token用于后续请求
        pm.environment.set("access_token", responseJson.token);
    }
});

Collection Runner配置

// 运行配置
{
  "collection": "User Management API",
  "environment": "Testing",
  "data": "login_test_data.csv",
  "iterations": 5,
  "delay": 100,
  "folder": "Authentication"
}

// 批量运行脚本
const newman = require('newman');

newman.run({
    collection: require('./collection.json'),
    environment: require('./environment.json'),
    data: './test_data.csv',
    reporters: ['html', 'json'],
    reporter: {
        html: {
            export: './report.html'
        },
        json: {
            export: './report.json'
        }
    }
}, function (err) {
    if (err) { 
        console.error('Collection run encountered an error:', err);
    } else {
        console.log('Collection run completed successfully.');
    }
});

10. 团队协作

Workspace管理

Workspace类型:
├── Personal Workspace (个人工作区)
├── Team Workspace (团队工作区)
└── Partner Workspace (合作伙伴工作区)

权限级别:
├── Viewer (查看者) - 只能查看
├── Editor (编辑者) - 可以编辑但不能管理成员
└── Admin (管理员) - 完全控制权限

版本控制

// Collection版本管理
1. 右键Collection -> "Create Fork"
2.Fork中进行修改
3. 创建Pull Request
4. 团队审核后合并

// 版本标签
{
  "version": "1.2.0",
  "changelog": [
    "添加了用户认证API",
    "修复了分页参数问题", 
    "更新了错误处理逻辑"
  ]
}

协作最佳实践

// 1. 统一的命名规范
Collection命名: "[项目名] API Collection"
Request命名: "[HTTP方法] [资源名] - [简短描述]"
变量命名: snake_case 或 camelCase

// 2. 完善的文档
/**
 * 用户登录API
 * 
 * @description 验证用户凭据并返回访问令牌
 * @param {string} username 用户名
 * @param {string} password 密码
 * @returns {object} 包含token和用户信息的对象
 * 
 * @example
 * POST /api/v1/auth/login
 * {
 *   "username": "admin",
 *   "password": "password123"
 * }
 */

// 3. 环境隔离
开发环境: dev-environment
测试环境: test-environment  
预生产环境: staging-environment
生产环境: prod-environment

// 4. 敏感信息管理
// 使用Initial Value和Current Value分离
Initial Value: {{secret_placeholder}}
Current Value: actual_secret_value

11. 高级功能

Mock Servers

// 创建Mock Server
1.Collection中添加Examples
2. 右键Collection -> "Mock Collection"
3. 配置Mock URL和响应

// Example响应配置
{
  "status": "success",
  "data": {
    "users": [
      {
        "id": 1,
        "name": "张三",
        "email": "zhangsan@example.com"
      },
      {
        "id": 2, 
        "name": "李四",
        "email": "lisi@example.com"
      }
    ]
  },
  "pagination": {
    "current_page": 1,
    "total_pages": 5,
    "per_page": 10,
    "total_count": 50
  }
}

// 动态Mock响应
pm.test("动态Mock数据", function () {
    const responseJson = pm.response.json();
    
    // 根据请求参数返回不同响应
    const page = pm.request.url.query.get("page") || 1;
    const limit = pm.request.url.query.get("limit") || 10;
    
    pm.expect(responseJson.pagination.current_page).to.equal(parseInt(page));
    pm.expect(responseJson.data.length).to.be.at.most(parseInt(limit));
});

Monitors

// 监控配置
{
  "name": "API健康检查",
  "collection": "Health Check Collection",
  "environment": "Production",
  "schedule": {
    "cron": "0 */5 * * * *",  // 每5分钟执行一次
    "timezone": "Asia/Shanghai"
  },
  "notifications": {
    "email": ["admin@example.com"],
    "slack": "webhook_url"
  }
}

// 监控测试脚本
pm.test("API服务可用性", function () {
    pm.expect(pm.response.code).to.equal(200);
    pm.expect(pm.response.responseTime).to.be.below(2000);
    
    const responseJson = pm.response.json();
    pm.expect(responseJson.status).to.equal("healthy");
    
    // 检查关键服务状态
    pm.expect(responseJson.services.database).to.equal("up");
    pm.expect(responseJson.services.cache).to.equal("up");
    pm.expect(responseJson.services.queue).to.equal("up");
});

// 自定义通知
pm.test("服务异常通知", function () {
    if (pm.response.code !== 200 || pm.response.responseTime > 5000) {
        // 发送自定义通知
        pm.sendRequest({
            url: "https://hooks.slack.com/your-webhook-url",
            method: 'POST',
            header: {
                'Content-Type': 'application/json'
            },
            body: {
                mode: 'raw',
                raw: JSON.stringify({
                    text: `🚨 API异常告警`,
                    attachments: [{
                        color: "danger",
                        fields: [{
                            title: "状态码",
                            value: pm.response.code,
                            short: true
                        }, {
                            title: "响应时间", 
                            value: pm.response.responseTime + "ms",
                            short: true
                        }]
                    }]
                })
            }
        }, function (err, response) {
            if (err) {
                console.error("通知发送失败:", err);
            }
        });
    }
});

Newman CLI

# 安装Newman
npm install -g newman

# 基本运行
newman run collection.json

# 使用环境文件
newman run collection.json -e environment.json

# 数据驱动测试
newman run collection.json -d test_data.csv

# 生成报告
newman run collection.json -r html,json --reporter-html-export report.html

# CI/CD集成
newman run collection.json \
  --environment production.json \
  --reporters cli,json \
  --reporter-json-export results.json \
  --timeout-request 30000 \
  --delay-request 100

12. 实战案例

电商API测试完整流程

1. 项目结构

电商API测试/
├── 00-Setup/
│   ├── 获取API Token
│   └── 环境检查
├── 01-用户管理/
│   ├── 用户注册
│   ├── 用户登录
│   ├── 获取用户信息
│   └── 更新用户信息
├── 02-商品管理/
│   ├── 商品列表
│   ├── 商品详情
│   ├── 商品搜索
│   └── 商品分类
├── 03-购物车/
│   ├── 添加商品到购物车
│   ├── 查看购物车
│   ├── 更新购物车数量
│   └── 清空购物车
├── 04-订单管理/
│   ├── 创建订单
│   ├── 查看订单
│   ├── 取消订单
│   └── 订单状态更新
└── 99-清理/
    └── 测试数据清理

2. 环境配置

// 开发环境
{
  "name": "E-commerce Dev",
  "values": [
    {"key": "base_url", "value": "http://localhost:3000/api/v1"},
    {"key": "admin_username", "value": "admin"},
    {"key": "admin_password", "value": "admin123"},
    {"key": "test_user_email", "value": "test@example.com"},
    {"key": "test_user_password", "value": "test123"}
  ]
}

// 生产环境
{
  "name": "E-commerce Prod",
  "values": [
    {"key": "base_url", "value": "https://api.example.com/v1"},
    {"key": "admin_username", "value": "{{admin_user}}"},
    {"key": "admin_password", "value": "{{admin_pass}}"}
  ]
}

3. Collection级别Pre-request Script

// 自动获取和刷新认证token
const tokenUrl = pm.environment.get("base_url") + "/auth/login";
const username = pm.environment.get("admin_username");
const password = pm.environment.get("admin_password");
const tokenExpiry = pm.environment.get("token_expiry");
const currentTime = new Date().getTime();

// 检查token是否需要刷新
if (!pm.environment.get("access_token") || 
    (tokenExpiry && currentTime > parseInt(tokenExpiry))) {
    
    console.log("🔑 获取新的访问token...");
    
    pm.sendRequest({
        url: tokenUrl,
        method: 'POST',
        header: {
            'Content-Type': 'application/json'
        },
        body: {
            mode: 'raw',
            raw: JSON.stringify({
                username: username,
                password: password
            })
        }
    }, function (err, response) {
        if (err) {
            console.error("❌ 认证失败:", err);
            return;
        }
        
        if (response.code === 200) {
            const responseJson = response.json();
            const token = responseJson.data.access_token;
            const expiresIn = responseJson.data.expires_in * 1000;
            const expiryTime = currentTime + expiresIn;
            
            pm.environment.set("access_token", token);
            pm.environment.set("token_expiry", expiryTime.toString());
            
            console.log("✅ Token获取成功");
        } else {
            console.error("❌ 认证失败,状态码:", response.code);
        }
    });
}

// 设置通用请求头
pm.request.headers.add({
    key: 'X-Request-ID',
    value: pm.variables.replaceIn('{{$guid}}')
});

pm.request.headers.add({
    key: 'X-Timestamp',
    value: new Date().toISOString()
});

4. 用户注册API测试

// Pre-request Script
const randomEmail = pm.variables.replaceIn('{{$randomEmail}}');
const randomPassword = pm.variables.replaceIn('{{$randomPassword}}');

pm.environment.set("new_user_email", randomEmail);
pm.environment.set("new_user_password", randomPassword);

// 请求体
{
  "email": "{{new_user_email}}",
  "password": "{{new_user_password}}",
  "first_name": "{{$randomFirstName}}",
  "last_name": "{{$randomLastName}}",
  "phone": "{{$randomPhoneNumber}}"
}

// Tests
pm.test("用户注册成功", function () {
    pm.expect(pm.response.code).to.equal(201);
    
    const responseJson = pm.response.json();
    pm.expect(responseJson.status).to.equal("success");
    pm.expect(responseJson.data).to.have.property('user');
    pm.expect(responseJson.data.user).to.have.property('id');
    pm.expect(responseJson.data.user.email).to.equal(pm.environment.get("new_user_email"));
    
    // 保存用户ID用于后续测试
    pm.environment.set("new_user_id", responseJson.data.user.id);
    
    console.log("✅ 新用户创建成功,ID:", responseJson.data.user.id);
});

pm.test("注册响应包含必要字段", function () {
    const responseJson = pm.response.json();
    const user = responseJson.data.user;
    
    pm.expect(user).to.have.all.keys(
        'id', 'email', 'first_name', 'last_name', 
        'phone', 'created_at', 'updated_at'
    );
    
    // 验证字段类型
    pm.expect(user.id).to.be.a('number');
    pm.expect(user.email).to.be.a('string');
    pm.expect(user.created_at).to.match(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/);
});

// 重复邮箱注册测试
pm.test("重复邮箱注册应该失败", function () {
    // 这个测试需要在Collection Runner中运行两次
    if (pm.info.iteration > 0) {
        pm.expect(pm.response.code).to.equal(400);
        
        const responseJson = pm.response.json();
        pm.expect(responseJson.error.message).to.include("already exists");
    }
});

5. 商品搜索API测试

// 测试数据
const searchTestData = [
    { keyword: "手机", expected_min_results: 1 },
    { keyword: "iPhone", expected_min_results: 1 },
    { keyword: "不存在的商品", expected_min_results: 0 },
    { keyword: "", expected_min_results: 0 }
];

// URL: {{base_url}}/products/search?q={{search_keyword}}&page={{page}}&limit={{limit}}

// Pre-request Script
const testIndex = pm.info.iteration % searchTestData.length;
const currentTest = searchTestData[testIndex];

pm.environment.set("search_keyword", currentTest.keyword);
pm.environment.set("expected_min_results", currentTest.expected_min_results);
pm.environment.set("page", 1);
pm.environment.set("limit", 20);

// Tests
pm.test("商品搜索 - " + pm.environment.get("search_keyword"), function () {
    const expectedMinResults = parseInt(pm.environment.get("expected_min_results"));
    
    if (expectedMinResults > 0) {
        pm.expect(pm.response.code).to.equal(200);
        
        const responseJson = pm.response.json();
        pm.expect(responseJson.data.products.length).to.be.at.least(expectedMinResults);
        
        // 验证搜索结果相关性
        const keyword = pm.environment.get("search_keyword").toLowerCase();
        responseJson.data.products.forEach(product => {
            const titleMatch = product.name.toLowerCase().includes(keyword);
            const descMatch = product.description.toLowerCase().includes(keyword);
            pm.expect(titleMatch || descMatch).to.be.true;
        });
    } else {
        // 空关键词或无结果的情况
        if (pm.environment.get("search_keyword") === "") {
            pm.expect(pm.response.code).to.equal(400);
        } else {
            pm.expect(pm.response.code).to.equal(200);
            const responseJson = pm.response.json();
            pm.expect(responseJson.data.products.length).to.equal(0);
        }
    }
});

pm.test("搜索响应格式正确", function () {
    if (pm.response.code === 200) {
        const responseJson = pm.response.json();
        
        pm.expect(responseJson).to.have.property('data');
        pm.expect(responseJson.data).to.have.property('products');
        pm.expect(responseJson.data).to.have.property('pagination');
        
        pm.expect(responseJson.data.products).to.be.an('array');
        
        if (responseJson.data.products.length > 0) {
            const product = responseJson.data.products[0];
            pm.expect(product).to.have.all.keys(
                'id', 'name', 'description', 'price', 
                'category', 'image_url', 'stock_quantity'
            );
        }
    }
});

6. 购物流程集成测试

// Collection级别的工作流测试
pm.test("完整购物流程测试", function () {
    const workflowStatus = pm.environment.get("workflow_status") || "start";
    
    switch (workflowStatus) {
        case "user_created":
            // 验证用户创建后的状态
            pm.expect(pm.environment.get("new_user_id")).to.not.be.undefined;
            pm.environment.set("workflow_status", "ready_to_shop");
            break;
            
        case "product_added_to_cart":
            // 验证商品已添加到购物车
            const responseJson = pm.response.json();
            pm.expect(responseJson.data.cart.items.length).to.be.above(0);
            pm.environment.set("workflow_status", "ready_to_checkout");
            break;
            
        case "order_created":
            // 验证订单创建成功
            const orderJson = pm.response.json();
            pm.expect(orderJson.data.order.status).to.equal("pending");
            pm.environment.set("order_id", orderJson.data.order.id);
            pm.environment.set("workflow_status", "order_completed");
            break;
    }
});

// 性能基准测试
pm.test("性能基准检查", function () {
    const responseTime = pm.response.responseTime;
    const endpoint = pm.request.url.getPath();
    
    // 不同端点的性能要求
    const performanceThresholds = {
        "/auth/login": 1000,
        "/products": 2000,
        "/products/search": 3000,
        "/cart": 1500,
        "/orders": 2000
    };
    
    const threshold = performanceThresholds[endpoint] || 2000;
    
    pm.expect(responseTime).to.be.below(threshold, 
        `${endpoint} 响应时间 ${responseTime}ms 超过阈值 ${threshold}ms`);
    
    // 记录性能数据
    console.log(`📊 ${endpoint}: ${responseTime}ms`);
});

7. 数据清理脚本

// 测试数据清理 Pre-request Script
const testUserId = pm.environment.get("new_user_id");
const testOrderId = pm.environment.get("order_id");

if (testUserId) {
    console.log("🧹 清理测试用户:", testUserId);
    
    // 删除测试订单
    if (testOrderId) {
        pm.sendRequest({
            url: pm.environment.get("base_url") + "/orders/" + testOrderId,
            method: 'DELETE',
            header: {
                'Authorization': 'Bearer ' + pm.environment.get("access_token")
            }
        }, function (err, response) {
            if (!err && response.code === 200) {
                console.log("✅ 测试订单已删除");
            }
        });
    }
    
    // 清空购物车
    pm.sendRequest({
        url: pm.environment.get("base_url") + "/cart/clear",
        method: 'POST',
        header: {
            'Authorization': 'Bearer ' + pm.environment.get("access_token")
        }
    }, function (err, response) {
        if (!err && response.code === 200) {
            console.log("✅ 购物车已清空");
        }
    });
}

// 清理环境变量
const cleanupVars = [
    "new_user_id", "new_user_email", "new_user_password",
    "order_id", "cart_item_id", "workflow_status"
];

cleanupVars.forEach(varName => {
    pm.environment.unset(varName);
});

console.log("✅ 环境变量已清理");

这个完整的指南涵盖了Postman的所有主要功能和最佳实践。通过这些示例和技巧,你可以构建强大的API测试套件,实现自动化测试,并有效地进行团队协作。记住,好的API测试不仅要验证功能正确性,还要关注性能、安全性和用户体验。

Similar code found with 3 license types