本章介紹軟體測試的工程實踐,包括測試環境管理、測試資料管理、持續測試整合,以及測試報告與度量。
測試計劃#
測試計劃的重要性在敏捷開發模式下依然存在,只是從一次性集中制定變成了以迭代的方式持續制定。
測試計劃的五大要素#
| 要素 | 核心問題 | 內容 |
|---|---|---|
| 測試範圍 | 測什麼?不測什麼? | 明確測試邊界 |
| 測試策略 | 先測什麼?如何測? | 測試優先級和方法 |
| 測試資源 | 誰來測?在哪測? | 人員和環境 |
| 測試進度 | 何時開始?何時完成? | 時間表和里程碑 |
| 風險預估 | 可能出什麼問題? | 風險識別和應對 |
測試策略制定#
測試策略考慮因素:
├── 測試類型選擇
│ ├── 功能測試 ─── 核心業務流程優先
│ ├── 效能測試 ─── 關鍵效能指標
│ ├── 安全測試 ─── 高風險功能
│ └── 兼容性測試 ─── 目標用戶設備
├── 自動化策略
│ ├── 哪些適合自動化
│ ├── 框架選型
│ └── 投入產出比
└── 回歸策略
└── 20% 精力覆蓋 80% 核心場景測試環境管理#
環境類型#
| 環境 | 用途 | 資料 |
|---|---|---|
| 開發環境 | 開發自測 | 開發資料 |
| 測試環境 | 功能測試 | 測試資料 |
| 預發布環境 | 上線前驗證 | 脫敏生產資料 |
| 生產環境 | 真實用戶使用 | 真實資料 |
環境管理挑戰#
常見問題及解決方案:
├── 環境不一致 ─────────→ 容器化、基礎設施即程式碼
├── 環境爭用 ─────────────→ 環境隔離、動態創建
├── 組態管理混亂 ─────────→ 組態中心、版本控制
└── 資料同步困難 ─────────→ 資料管理平台容器化測試環境#
# Docker Compose 測試環境示例
version: "3"
services:
app:
build: .
ports:
- "8080:8080"
depends_on:
- db
- redis
environment:
- SPRING_PROFILES_ACTIVE=test
db:
image: mysql:8.0
environment:
- MYSQL_ROOT_PASSWORD=test
- MYSQL_DATABASE=testdb
redis:
image: redis:6基礎設施即程式碼:使用 Docker、Kubernetes 等工具將測試環境組態程式碼化,確保環境的一致性和可重複性。
測試資料管理#
資料準備策略#
| 策略 | 說明 | 適用場景 |
|---|---|---|
| On-the-fly | 測試時實時創建 | 一次性資料(訂單、優惠券) |
| Out-of-box | 預先準備好 | 穩定資料(商品類目、品牌) |
| 混合方式 | 結合兩種方式 | 實際項目中最常用 |
資料創建技術#
資料創建方式:
├── API 呼叫
│ ├── 優點:資料準確性高
│ └── 缺點:不是所有資料都有 API
├── 資料庫操作
│ ├── 優點:效率高、靈活
│ └── 缺點:需要維護 SQL 與程式碼同步
└── 綜合方式
└── API 創建基礎資料,SQL 修改特定狀態測試資料工具設計#
// 測試資料工具示例
public class TestDataFactory {
// 創建測試用戶
public User createUser() {
return createUser(UserType.NORMAL);
}
public User createUser(UserType type) {
User user = apiClient.createUser(generateUserData());
if (type == UserType.VIP) {
// 通過 SQL 修改用戶類型
jdbcTemplate.update(
"UPDATE users SET type = 'VIP' WHERE id = ?",
user.getId()
);
}
return user;
}
// 創建測試訂單
public Order createOrder(User buyer, Product product) {
return apiClient.createOrder(
buyer.getId(),
product.getId()
);
}
}資料隔離原則#
測試資料污染是自動化測試不穩定的主要原因之一。每個測試用例應該創建自己的資料,或使用唯一標識區分。
資料隔離策略:
├── 唯一標識 ─── 測試資料帶唯一前綴/後綴
├── 事務回滾 ─── 測試結束後回滾資料變更
├── 獨立資料集 ─── 每個測試用例使用獨立資料
└── 清理策略 ─── 測試後自動清理測試資料持續測試(CI/CD 整合)#
測試金字塔在 CI/CD 中的應用#
┌─────────────────────────────────────────────────────────┐
│ CI/CD 測試流水線 │
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 程式碼提交 │ │
│ └────────────────────┬────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 單元測試 (秒級) │ │
│ │ - 每次提交都執行 │ │
│ │ - 阻斷部署條件:失敗 │ │
│ └────────────────────┬────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 整合測試 (分鐘級) │ │
│ │ - 每次提交或合併請求執行 │ │
│ │ - 阻斷部署條件:失敗 │ │
│ └────────────────────┬────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ E2E 測試 (10-30 分鐘) │ │
│ │ - 部署到測試環境後執行 │ │
│ │ - 阻斷部署條件:關鍵用例失敗 │ │
│ └────────────────────┬────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 效能/安全測試 (定時或手動觸發) │ │
│ └─────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘Jenkins Pipeline 示例#
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'mvn clean compile'
}
}
stage('Unit Tests') {
steps {
sh 'mvn test'
}
post {
always {
junit 'target/surefire-reports/*.xml'
jacoco(execPattern: '**/target/jacoco.exec')
}
}
}
stage('Integration Tests') {
steps {
sh 'mvn verify -P integration-test'
}
}
stage('Deploy to Test') {
steps {
sh 'deploy-to-test.sh'
}
}
stage('E2E Tests') {
steps {
sh 'mvn verify -P e2e-test'
}
post {
always {
publishHTML([
reportDir: 'target/e2e-reports',
reportFiles: 'index.html',
reportName: 'E2E Test Report'
])
}
}
}
}
post {
failure {
slackSend channel: '#dev-alerts',
message: "Build Failed: ${env.JOB_NAME} ${env.BUILD_NUMBER}"
}
}
}測試失敗處理策略#
| 策略 | 說明 | 適用場景 |
|---|---|---|
| 快速失敗 | 發現失敗立即停止 | 單元測試 |
| 繼續執行 | 記錄失敗,繼續其他測試 | 整合測試、E2E 測試 |
| 重試機制 | 失敗後自動重試 | 不穩定的 E2E 測試 |
| 智能跳過 | 根據程式碼變更選擇性執行 | 大型測試套件 |
測試報告與度量#
關鍵測試指標#
測試度量指標:
├── 測試覆蓋率
│ ├── 需求覆蓋率
│ └── 程式碼覆蓋率(行/分支/條件)
├── 測試效率
│ ├── 用例執行時間
│ ├── 缺陷發現率
│ └── 缺陷逃逸率
├── 測試品質
│ ├── 用例通過率
│ ├── 缺陷重開率
│ └── 自動化穩定性
└── 測試進度
├── 用例完成率
└── 缺陷趨勢缺陷報告要素#
| 要素 | 說明 |
|---|---|
| 標題 | 在什麼情況下發生了什麼問題 |
| 概述 | 缺陷本質的概括性描述 |
| 影響 | 對用戶或業務的影響 |
| 環境 | 復現所需的環境資訊 |
| 前置條件 | 開始復現前的系統狀態 |
| 復現步驟 | 可操作的、連貫的步驟 |
| 期望/實際結果 | 應該發生什麼 vs 實際發生什麼 |
| 優先級/嚴重程度 | 修復的緊急程度和影響程度 |
好的缺陷報告不是大量資訊的堆疊,而是以高效的方式提供準確有用的資訊。
測試報告自動化#
自動化測試報告生成:
├── JUnit/TestNG XML 報告
├── JaCoCo 覆蓋率報告
├── Allure 富報告
│ ├── 測試用例詳情
│ ├── 歷史趨勢
│ ├── 附件(截圖、日誌)
│ └── 缺陷關聯
└── 自定義 Dashboard
└── Grafana + InfluxDB/Prometheus測試團隊協作#
測試工程師的角色#
測試工程師是項目的「潤滑劑」:
├── 對接產品經理 ─── 確保需求正確實現
├── 對接開發人員 ─── 確保缺陷及時修復
├── 對接運維人員 ─── 確保環境穩定
└── 對接用戶 ─────── 確保用戶體驗敏捷測試實踐#
| 實踐 | 說明 |
|---|---|
| 測試左移 | 測試人員早期介入需求分析 |
| 持續測試 | 自動化測試融入 CI/CD |
| 探索性測試 | 邊測試邊學習,發現未知問題 |
| 結對測試 | 開發和測試結對工作 |
| BDD | 行為驅動開發,用自然語言描述測試 |
BDD 示例(Cucumber)#
# login.feature
Feature: 用戶登錄
作為一個註冊用戶
我希望能夠登錄系統
以便使用系統功能
Scenario: 正確的用戶名和密碼登錄成功
Given 我已經是一個註冊用戶
And 我的用戶名是 "testuser"
And 我的密碼是 "password123"
When 我在登錄頁面輸入用戶名和密碼
And 我點擊登錄按鈕
Then 我應該看到首頁
And 我應該看到歡迎資訊 "Hello, testuser"
Scenario: 錯誤的密碼登錄失敗
Given 我已經是一個註冊用戶
And 我的用戶名是 "testuser"
When 我輸入錯誤的密碼 "wrongpassword"
And 我點擊登錄按鈕
Then 我應該看到錯誤資訊 "用戶名或密碼錯誤"測試能力成熟度#
測試能力成熟度等級:
├── Level 1: 初始級
│ └── 測試是無序的、隨機的
├── Level 2: 可重複級
│ └── 有基本的測試流程,可重複執行
├── Level 3: 已定義級
│ └── 測試流程標準化,有專門的測試團隊
├── Level 4: 量化管理級
│ └── 測試過程可度量,有明確的質量指標
└── Level 5: 持續最佳化級
└── 持續改進測試過程,追求卓越測試不是終點,而是持續改進的過程。保持學習心態,關注測試技術的發展,不斷提升測試能力。