目录
- Postman基础介绍
- 界面布局和基本操作
- 请求管理
- 认证和授权
- 环境变量和全局变量
- Collection管理
- 脚本编写
- 测试和断言
- 数据驱动测试
- 团队协作
- 高级功能
- 实战案例
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