计算机网络学习指南计算机网络学习指南
首页
基础教程
进阶内容
实战案例
编程指南
首页
基础教程
进阶内容
实战案例
编程指南
  • 实战案例

    • 💼 实战案例
    • 🎯 学习目标
    • 🚀 学习路线
    • 📊 章节概览
  • 💡 学习建议
  • 🎓 学完之后
  • 第1章 - 前端开发的网络应用
  • 第2章 - 后端开发的网络应用
  • 第3章 - 运维与 DevOps
  • 第4章 - 测试与网络调试
  • 第5章 - 网络故障排查

第4章 - 测试中的网络调试

嗨,测试工程师朋友们!

作为测试工程师,你需要测试各种网络接口、分析网络请求、模拟各种网络环境……掌握网络调试技能可以让你更高效地发现和定位问题。

这一章,我会带你学习测试工作中最实用的网络调试技能和工具,让你成为网络测试专家!

🛠️ 接口测试工具

Postman 使用

基础请求

// GET 请求示例
GET https://api.example.com/users

Headers:
Authorization: Bearer {{access_token}}
Content-Type: application/json

// 使用环境变量
{{base_url}}/users/{{user_id}}

测试脚本

// Pre-request Script (请求前执行)
// 生成随机数据
pm.globals.set("random_email", `test${Math.random()}@example.com`);

// 获取当前时间戳
pm.globals.set("timestamp", Date.now());

// 从环境变量获取 token
const token = pm.environment.get("access_token");
console.log("Token:", token);
// Tests (响应后执行)
// 测试状态码
pm.test("Status code is 200", function () {
    pm.response.to.have.status(200);
});

// 测试响应时间
pm.test("Response time is less than 500ms", function () {
    pm.expect(pm.response.responseTime).to.be.below(500);
});

// 测试响应体
pm.test("Response has success field", function () {
    const jsonData = pm.response.json();
    pm.expect(jsonData).to.have.property('success');
    pm.expect(jsonData.success).to.be.true;
});

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

// 保存响应数据到环境变量
const responseData = pm.response.json();
if (responseData.data && responseData.data.id) {
    pm.environment.set("user_id", responseData.data.id);
    console.log("Saved user_id:", responseData.data.id);
}

// 验证数组
pm.test("Response has users array", function () {
    const jsonData = pm.response.json();
    pm.expect(jsonData.data).to.be.an('array');
    pm.expect(jsonData.data.length).to.be.above(0);
});

// 验证对象结构
pm.test("User has required fields", function () {
    const user = pm.response.json().data[0];
    pm.expect(user).to.have.property('id');
    pm.expect(user).to.have.property('name');
    pm.expect(user).to.have.property('email');
});

自动化测试集合

// Collection Runner 变量
// 创建 data.json 文件
[
  {
    "username": "user1",
    "email": "user1@example.com",
    "password": "password123"
  },
  {
    "username": "user2",
    "email": "user2@example.com",
    "password": "password456"
  }
]

// 在请求中使用
POST {{base_url}}/register

Body (JSON):
{
  "username": "{{username}}",
  "email": "{{email}}",
  "password": "{{password}}"
}

cURL 命令行测试

# GET 请求
curl -X GET "https://api.example.com/users"

# 带 Header 的请求
curl -X GET "https://api.example.com/users" \
  -H "Authorization: Bearer TOKEN123" \
  -H "Content-Type: application/json"

# POST 请求提交 JSON
curl -X POST "https://api.example.com/users" \
  -H "Content-Type: application/json" \
  -d '{"name":"张三","email":"zhangsan@example.com"}'

# POST 请求提交表单
curl -X POST "https://api.example.com/login" \
  -d "username=admin" \
  -d "password=123456"

# 上传文件
curl -X POST "https://api.example.com/upload" \
  -F "file=@/path/to/file.jpg" \
  -F "user_id=123"

# 保存响应到文件
curl -o response.json "https://api.example.com/users"

# 显示详细信息
curl -v "https://api.example.com/users"

# 只显示响应头
curl -I "https://api.example.com/users"

# 跟随重定向
curl -L "https://example.com"

# 设置超时
curl --connect-timeout 5 --max-time 10 "https://api.example.com/users"

# 使用代理
curl -x http://proxy.example.com:8080 "https://api.example.com/users"

# 忽略 SSL 证书验证
curl -k "https://api.example.com/users"

🔍 抓包分析

Chrome DevTools

// 使用 Chrome DevTools Network 面板

// 1. 打开 DevTools (F12)
// 2. 切换到 Network 标签
// 3. 刷新页面或触发请求

// 查看请求详情:
// - Headers: 请求头和响应头
// - Preview: 格式化的响应数据
// - Response: 原始响应数据
// - Timing: 请求各阶段耗时

// 过滤请求:
// - XHR: 只显示 Ajax 请求
// - JS: 只显示 JavaScript 文件
// - CSS: 只显示样式文件
// - Img: 只显示图片

// 性能分析:
// - DOMContentLoaded: DOM 加载完成时间(蓝线)
// - Load: 页面完全加载时间(红线)
// - 瀑布图: 查看资源加载顺序和耗时

Wireshark 抓包

基础使用

# 启动 Wireshark
# 选择网络接口(如 eth0 或 Wi-Fi)
# 点击开始捕获

# 常用过滤器
http                    # 只显示 HTTP 流量
http.request.method == "POST"  # 只显示 POST 请求
http.response.code == 404      # 只显示 404 响应

tcp.port == 80          # 只显示 80 端口的 TCP 流量
tcp.port == 443         # HTTPS 流量

ip.addr == 192.168.1.100  # 指定 IP 地址
ip.src == 192.168.1.100   # 源 IP
ip.dst == 192.168.1.100   # 目标 IP

# 组合过滤
http && ip.addr == 192.168.1.100
tcp.port == 80 || tcp.port == 443

# 排除过滤
!arp  # 排除 ARP 流量
!(tcp.port == 22)  # 排除 SSH 流量

分析 TCP 三次握手

# 过滤器: tcp.flags.syn == 1

# 观察三次握手过程:
# 1. SYN: 客户端 -> 服务器 (SYN=1, ACK=0)
# 2. SYN-ACK: 服务器 -> 客户端 (SYN=1, ACK=1)
# 3. ACK: 客户端 -> 服务器 (SYN=0, ACK=1)

# 右键数据包 -> Follow -> TCP Stream
# 可以看到完整的 TCP 会话内容

分析 HTTP 请求

# 过滤器: http.request

# 查看 HTTP 请求详情:
# - 请求方法 (GET/POST/PUT/DELETE)
# - 请求路径
# - 请求头 (User-Agent, Cookie, Authorization)
# - 请求体 (POST 数据)

# 过滤器: http.response

# 查看 HTTP 响应详情:
# - 状态码 (200, 404, 500)
# - 响应头 (Content-Type, Set-Cookie)
# - 响应体 (HTML, JSON)

Charles 代理

基础配置

# 1. 启动 Charles
# 2. Proxy -> Proxy Settings
#    - 端口设置: 8888
#    - 启用 "Enable transparent HTTP proxying"

# 3. 配置浏览器代理
#    - HTTP Proxy: 127.0.0.1:8888
#    - HTTPS Proxy: 127.0.0.1:8888

# 4. 安装 SSL 证书
#    - Help -> SSL Proxying -> Install Charles Root Certificate
#    - 信任该证书

# 5. 启用 SSL 代理
#    - Proxy -> SSL Proxying Settings
#    - 添加: *.example.com:443

修改请求/响应

// Breakpoints (断点)
// 右键请求 -> Breakpoints
// 可以修改请求头、请求体、响应头、响应体

// Map Local (映射本地文件)
// Tools -> Map Local
// 将远程资源映射到本地文件,测试修改后的代码

// Map Remote (映射远程地址)
// Tools -> Map Remote
// 将一个地址的请求重定向到另一个地址

// Rewrite (重写)
// Tools -> Rewrite
// 添加/修改/删除 请求头、响应头、请求参数

// Throttling (限速)
// Proxy -> Throttle Settings
// 模拟慢速网络环境

⚡ 性能测试

Apache Bench (ab)

# 基础压测
ab -n 1000 -c 10 http://example.com/
# -n: 总请求数
# -c: 并发数

# POST 请求
ab -n 1000 -c 10 -p data.json -T application/json http://example.com/api

# 带认证
ab -n 1000 -c 10 -H "Authorization: Bearer TOKEN" http://example.com/api

# 结果分析
# Time taken for tests: 总耗时
# Requests per second: 每秒请求数 (QPS)
# Time per request: 平均响应时间
# Transfer rate: 传输速率
# Percentage of requests: 响应时间百分位

JMeter 性能测试

基础测试计划

<!-- 测试计划结构 -->
Test Plan
  ├── Thread Group (线程组)
  │   ├── Number of Threads: 100 (虚拟用户数)
  │   ├── Ramp-Up Period: 10 (启动时间,秒)
  │   ├── Loop Count: 10 (循环次数)
  │   │
  │   ├── HTTP Request (HTTP 请求)
  │   │   ├── Server: api.example.com
  │   │   ├── Port: 443
  │   │   ├── Protocol: https
  │   │   ├── Method: GET
  │   │   ├── Path: /users
  │   │
  │   ├── HTTP Header Manager (请求头)
  │   │   ├── Authorization: Bearer ${token}
  │   │   ├── Content-Type: application/json
  │   │
  │   └── Assertions (断言)
  │       ├── Response Code: 200
  │       ├── Response Time: < 1000ms
  │
  ├── Listeners (监听器)
  │   ├── View Results Tree (查看结果树)
  │   ├── Summary Report (聚合报告)
  │   ├── Graph Results (图形结果)
  │   └── Response Time Graph (响应时间图)

使用变量和参数化

# users.csv (CSV 数据文件)
username,password,email
user1,pass123,user1@example.com
user2,pass456,user2@example.com
user3,pass789,user3@example.com

# 添加 CSV Data Set Config
# Filename: users.csv
# Variable Names: username,password,email

# 在请求中使用变量
# ${username}
# ${password}
# ${email}

🌐 Mock 测试

Mock Server (使用 json-server)

# 安装 json-server
npm install -g json-server

# 创建 db.json
cat > db.json << EOF
{
  "users": [
    { "id": 1, "name": "张三", "email": "zhangsan@example.com" },
    { "id": 2, "name": "李四", "email": "lisi@example.com" }
  ],
  "posts": [
    { "id": 1, "title": "文章1", "userId": 1 },
    { "id": 2, "title": "文章2", "userId": 2 }
  ]
}
EOF

# 启动 Mock 服务器
json-server --watch db.json --port 3000

# 现在可以访问:
# GET    /users          # 获取所有用户
# GET    /users/1        # 获取单个用户
# POST   /users          # 创建用户
# PUT    /users/1        # 更新用户
# DELETE /users/1        # 删除用户
# GET    /users?name=张三 # 过滤查询

使用 Postman Mock Server

// 1. 在 Postman 中创建 Collection
// 2. 点击 "Mock Servers" -> "Create Mock Server"
// 3. 为每个请求添加 Example

// Example 响应示例:
{
  "success": true,
  "data": [
    {
      "id": 1,
      "name": "张三",
      "email": "zhangsan@example.com"
    }
  ]
}

// 使用 Mock Server URL
// https://xxxxx.mock.pstmn.io/users

🔧 网络异常测试

弱网模拟

Chrome DevTools 网络限速

// 1. 打开 DevTools (F12)
// 2. 切换到 Network 标签
// 3. 点击 "No throttling" 下拉菜单

// 预设选项:
// - Fast 3G: 1.5Mbps 下载, 750Kbps 上传, 100ms 延迟
// - Slow 3G: 500Kbps 下载, 500Kbps 上传, 400ms 延迟
// - Offline: 模拟离线

// 自定义网络条件:
// - Download: 下载速度
// - Upload: 上传速度
// - Latency: 延迟时间

Linux 网络限速 (tc 命令)

# 添加延迟 (100ms)
sudo tc qdisc add dev eth0 root netem delay 100ms

# 添加延迟波动
sudo tc qdisc add dev eth0 root netem delay 100ms 20ms

# 添加丢包率 (10%)
sudo tc qdisc add dev eth0 root netem loss 10%

# 限制带宽 (1Mbps)
sudo tc qdisc add dev eth0 root tbf rate 1mbit burst 32kbit latency 400ms

# 组合条件
sudo tc qdisc add dev eth0 root netem delay 100ms loss 5% rate 1mbit

# 查看当前设置
sudo tc qdisc show dev eth0

# 删除限制
sudo tc qdisc del dev eth0 root

超时测试

// 测试连接超时
fetch('https://api.example.com/users', {
  signal: AbortSignal.timeout(5000)  // 5秒超时
})
  .then(response => response.json())
  .catch(error => {
    if (error.name === 'TimeoutError') {
      console.log('请求超时');
    }
  });

// 手动实现超时
const timeout = (ms) => new Promise((_, reject) => 
  setTimeout(() => reject(new Error('Timeout')), ms)
);

Promise.race([
  fetch('https://api.example.com/users'),
  timeout(5000)
])
  .then(response => response.json())
  .catch(error => console.error('请求失败:', error));

错误场景测试

# 测试 DNS 解析失败
curl http://nonexistent-domain-12345.com

# 测试连接被拒绝
curl http://localhost:9999

# 测试 SSL 证书错误
curl https://self-signed.badssl.com/

# 测试各种 HTTP 状态码
curl https://httpstat.us/200  # 成功
curl https://httpstat.us/400  # 错误请求
curl https://httpstat.us/401  # 未授权
curl https://httpstat.us/404  # 未找到
curl https://httpstat.us/500  # 服务器错误
curl https://httpstat.us/503  # 服务不可用

# 测试超时
curl --max-time 1 https://httpstat.us/200?sleep=5000

📊 测试报告

性能测试报告模板

# 性能测试报告

## 测试环境
- 测试时间: 2024-01-01 10:00:00
- 测试工具: JMeter 5.5
- 服务器: 4核8G, Ubuntu 22.04
- 数据库: MySQL 8.0

## 测试场景

### 场景1: 用户列表查询
- 接口: GET /api/users
- 并发数: 100
- 持续时间: 5分钟
- 目标: QPS > 1000, 响应时间 < 200ms

## 测试结果

| 指标 | 值 | 目标 | 是否达标 |
|------|-----|------|----------|
| 总请求数 | 50000 | - | - |
| 成功率 | 99.8% | > 99% | ✅ |
| QPS | 1167 | > 1000 | ✅ |
| 平均响应时间 | 85ms | < 200ms | ✅ |
| 95%响应时间 | 156ms | < 300ms | ✅ |
| 99%响应时间 | 234ms | < 500ms | ✅ |
| 最大响应时间 | 567ms | - | - |

## 性能瓶颈

1. 数据库查询较慢 (平均 50ms)
2. 网络延迟 (平均 15ms)

## 优化建议

1. 添加数据库索引
2. 启用查询缓存
3. 使用 CDN 加速静态资源

自动化测试脚本

// test-api.js
const axios = require('axios');

const BASE_URL = 'https://api.example.com';
const results = [];

// 测试用例
const testCases = [
  {
    name: '获取用户列表',
    method: 'GET',
    url: '/users',
    expectedStatus: 200,
    validateResponse: (data) => Array.isArray(data.data)
  },
  {
    name: '创建用户',
    method: 'POST',
    url: '/users',
    data: { name: '测试用户', email: 'test@example.com' },
    expectedStatus: 201,
    validateResponse: (data) => data.success === true
  },
  {
    name: '获取不存在的用户',
    method: 'GET',
    url: '/users/99999',
    expectedStatus: 404
  }
];

// 运行测试
async function runTests() {
  console.log('开始测试...\n');
  
  for (const testCase of testCases) {
    try {
      const startTime = Date.now();
      
      const response = await axios({
        method: testCase.method,
        url: BASE_URL + testCase.url,
        data: testCase.data
      });
      
      const duration = Date.now() - startTime;
      
      // 验证状态码
      const statusMatch = response.status === testCase.expectedStatus;
      
      // 验证响应内容
      let responseValid = true;
      if (testCase.validateResponse) {
        responseValid = testCase.validateResponse(response.data);
      }
      
      const passed = statusMatch && responseValid;
      
      results.push({
        name: testCase.name,
        passed,
        duration,
        status: response.status,
        message: passed ? '✅ 通过' : '❌ 失败'
      });
      
      console.log(`${testCase.name}: ${results[results.length - 1].message} (${duration}ms)`);
      
    } catch (error) {
      const expectedError = error.response?.status === testCase.expectedStatus;
      
      results.push({
        name: testCase.name,
        passed: expectedError,
        status: error.response?.status || 'Error',
        message: expectedError ? '✅ 通过' : '❌ 失败',
        error: error.message
      });
      
      console.log(`${testCase.name}: ${results[results.length - 1].message}`);
    }
  }
  
  // 输出汇总
  console.log('\n=== 测试汇总 ===');
  const passed = results.filter(r => r.passed).length;
  const total = results.length;
  console.log(`通过: ${passed}/${total}`);
  console.log(`成功率: ${(passed / total * 100).toFixed(2)}%`);
}

runTests();

💡 最佳实践

1. 测试用例设计

// 边界值测试
const testCases = [
  { input: -1, expected: 'error' },    // 负数
  { input: 0, expected: 'error' },     // 零
  { input: 1, expected: 'success' },   // 最小正数
  { input: 100, expected: 'success' }, // 正常值
  { input: 999, expected: 'success' }, // 最大值
  { input: 1000, expected: 'error' }   // 超过最大值
];

// 异常情况测试
const errorTestCases = [
  { desc: '缺少必填参数', data: {} },
  { desc: '参数类型错误', data: { id: 'abc' } },
  { desc: '参数格式错误', data: { email: 'invalid' } },
  { desc: '请求体过大', data: 'x'.repeat(10000000) }
];

2. 测试环境隔离

// 配置不同环境
const environments = {
  dev: {
    baseURL: 'http://localhost:3000',
    timeout: 10000
  },
  test: {
    baseURL: 'https://test-api.example.com',
    timeout: 5000
  },
  prod: {
    baseURL: 'https://api.example.com',
    timeout: 3000
  }
};

const env = process.env.NODE_ENV || 'dev';
const config = environments[env];

const api = axios.create(config);

3. 持续集成

# .github/workflows/api-test.yml
name: API Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v2
      
      - name: Setup Node.js
        uses: actions/setup-node@v2
        with:
          node-version: '16'
      
      - name: Install dependencies
        run: npm install
      
      - name: Run tests
        run: npm test
      
      - name: Upload test results
        if: always()
        uses: actions/upload-artifact@v2
        with:
          name: test-results
          path: test-results/

📝 小结

这一章我们学习了:

✅ 接口测试工具:Postman、cURL、自动化脚本
✅ 抓包分析:Chrome DevTools、Wireshark、Charles
✅ 性能测试:ab、JMeter、压力测试
✅ Mock 测试:Mock Server、数据模拟
✅ 异常测试:弱网模拟、超时测试、错误场景
✅ 测试报告:结果分析、自动化测试

🎯 下一步

最后一章,学习如何排查和解决常见的网络问题!

继续学习第5章:网络问题排查 →

最近更新: 2025/12/27 10:13
Contributors: 王长安
Prev
第3章 - 运维与 DevOps
Next
第5章 - 网络故障排查