遺留代碼往往缺乏測試,重構前必須建立測試保護網。本文介紹 PHP 腳本級測試的核心思路:模擬 HTTP 請求、捕獲響應、隔離依賴,並實戰演示 SimpleTest 框架的 Web 測試能力。
| 難點 | 解決方案 |
| 腳本無直接入口(非 Web 可訪問) | 建立測試包裝類,模擬 $_GET/$_POST/$_SERVER |
| 直接輸出 (echo/print) 難以捕獲 | 用 ob_start()/ob_get_clean() 緩衝捕獲輸出 |
| header() 等內置函數干擾測試環境 | 封裝為對象方法 $this->header(),測試時攔截記錄 |
| 數據庫/外部服務依賴 | 注入 Mock 連接或使用 SQLite 內存庫 |
二、測試包裝類模式
<?php
class ForumPostingTestWrapper {
private $headers = [];
public function handleRequest(array $postData) {
$_POST = $postData; // 模擬 POST 請求
// 可按需模擬 $_GET, $_SERVER, $_COOKIE, $_FILES
ob_start(); // 開啟輸出緩衝
include 'forum/post_new_copy.php'; // 包含被測腳本副本
$content = ob_get_clean(); // 獲取並清空緩衝
return [
'content' => $content,
'headers' => $this->headers
];
}
// 攔截 header() 呼叫
public function header($line) {
$this->headers[] = $line;
}
// 可擴展:攔截 exit/die、setcookie、session_start 等
}
三、測試用例
// 使用 PHPUnit 風格斷言(或 SimpleTest)
$wrapper = new ForumPostingTestWrapper();
$response = $wrapper->handleRequest([
'id_thread' => 42,
'text' => 'Hello, world',
'author' => 'tester'
]);
// 斷言響應內容
assertStringContainsString('發布成功', $response['content']);
// 斷言 Header
assertContains('Content-Type: text/html', $response['headers']);
四、副本策略:最小化修改
- 複製原腳本為
post_new_copy.php
- 移除未使用的
include/require
- 將內置函數調用改為對象方法:
header() → $this->header()
- 將全局資源(DB 連接)改為對象屬性注入
測試通過後,將邏輯遷移回原腳本或重構為類庫,副本可刪除。
五、SimpleTest 實戰:Web 測試框架
SimpleTest 內建 WebTestCase,支援完整 HTTP 交互模擬(GET/POST/點擊鏈接/提交表單/斷言標題/內容/表單字段)。
安裝
下載源碼包解壓至項目目錄,require_once 'simpletest/autorun.php' 即可使用。
案例 1:檢查網站可訪問
require_once 'simpletest/web_tester.php';
class SiteAvailabilityTest extends WebTestCase {
function testHomepageLoads() {
$this->get('https://example.com/');
$this->assertResponse(200);
$this->assertTitle('Example Domain');
$this->assertWantedPattern('/Example Domain/');
}
}
// 運行
$test = new SiteAvailabilityTest();
$test->run(new HtmlReporter());
案例 2:完整登錄流程測試
class LoginFlowTest extends WebTestCase {
function testValidLogin() {
// 1. 獲取登錄頁
$this->get('https://app.example.com/login.php');
// 2. 填寫表單
$this->setField('username', 'testuser');
$this->setField('password', 'secret123');
// 3. 提交
$this->clickSubmit('登錄');
// 4. 斷言登錄成功
$this->assertResponse(200);
$this->assertWantedPattern('/歡迎回來/');
$this->assertTitle('用戶中心');
// 5. 點擊進入管理頁
$this->clickLink('管理後台');
$this->assertTitle('管理中心');
$this->assertWantedPattern('/請選擇操作/');
// 6. 登出
$this->clickLink('退出登錄');
$this->assertWantedPattern('/已登出/');
}
}
SimpleTest 核心 API 速查
| 方法 | 用途 |
| get($url) | 發送 GET 請求 |
| post($url, $data) | 發送 POST 請求 |
| setField($name, $value) | 設置表單字段值 |
| clickSubmit($label) | 點擊提交按鈕(按 value/alt/text 匹配) |
| clickLink($label) | 點擊鏈接(按文本匹配) |
| assertResponse($code) | 斷言 HTTP 狀態碼 |
| assertTitle($title) | 斷言頁面標題 |
| assertWantedPattern($regex) | 斷言響應體匹配正則 |
| assertNoUnwantedPattern($regex) | 斷言響應體不匹配正則 |
| assertField($name, $value) | 斷言表單字段值 |
六、PHP 單元測試工具包對比
| 工具 | 特點 | 推薦指數 |
| PHPUnit | 標準化、生態最豐富、CI/CD 集成完美、支援數據提供者/模擬對象/代碼覆蓋率 | ⭐⭐⭐⭐⭐ |
| SimpleTest | 內建 WebTestCase、適合舊專案快速加測試、無需 Composer、文檔簡單 | ⭐⭐⭐ |
| Codeception | 支援單元/功能/驗收測試、BDD 風格、模組化架構 | ⭐⭐⭐⭐ |
| PHPSpec | BDD 規範驅動、設計優先 | ⭐⭐⭐ |
建議:新專案首選 PHPUnit;維護無 Composer 的舊專案,SimpleTest 是零配置快速上手的最佳選擇。
- 上一篇文章: ThinkPHP 開發移動端 API 接口實戰:標準化響應結構與自動模板切換雙方案
- 下一篇文章: PHP 實現 Discuz 用戶合併:直接導入 uc_members 表與 UCenter 整合雙方案詳解
Copyright ©
程式碼之家 All Rights Reserved