核心要點
trigger_error()
函數的代碼時可能會導致問題。 trigger_error()
的代碼,可以使用自定義錯誤處理程序來捕獲錯誤信息,以便稍後使用斷言進行分析。這允許代碼繼續執行,同時仍然允許檢查引發的錯誤條件。 假設您正在維護使用 PHP 原生 trigger_error()
函數記錄錯誤信息的代碼。同時,您正在使用 PHPUnit 為該代碼編寫單元測試。如果您參考 PHPUnit 手冊,有一節內容專門介紹如何測試錯誤條件。它描述了 PHPUnit 如何實現自己的錯誤處理程序,該處理程序將錯誤、警告和通知轉換為異常,並且捕獲這些異常是您應該如何處理此類錯誤測試的方法。但是,根據您的代碼外觀,您可能會遇到 PHPUnit 的這種方法的問題。本文將詳細說明這個問題是什麼,它如何影響您測試代碼的能力,以及如何解決它。
問題是什麼?
錯誤和異常的行為方式根本不同。與本文特別相關的是,如果傳遞給它的錯誤級別常量不表示致命錯誤,則代碼執行可以在 trigger_error()
之後立即繼續。當拋出異常時,執行將在找到與該異常類對應的 catch
塊的開頭繼續,這可能在拋出異常的點之後立即發生,也可能不會。讓我們來看一些這些行為的示例。首先是錯誤。
<code class="language-php"><?php error_reporting(E_ALL | E_STRICT); echo "Before warning\n"; trigger_error("Danger Will Robinson!", E_USER_WARNING); echo "After warning\n"; ?></code>
如果您運行上述代碼,您將獲得以下輸出:
<code>Before warning PHP Warning: Danger Will Robinson! in /home/matt/error_handler.php on line 4 After warning</code>
由此可見,trigger_error()
調用後的 echo
語句已執行。現在,異常。
<code class="language-php"><?php try { echo "Before exception\n"; throw new Exception("Danger Will Robinson!"); echo "After exception\n"; } catch (Exception $e) { echo "In catch block\n"; } ?></code>
輸出:
<code>Before exception In catch block</code>
與錯誤示例相反,拋出異常後的代碼未執行。因為 PHPUnit 將錯誤轉換為異常,所以錯誤在單元測試中的行為與異常相同。在測試期間,任何在觸發錯誤後執行的代碼都不會執行。再舉一個例子:
<code class="language-php"><?php function foo($param) { if (is_string($param)) { trigger_error(__FUNCTION__ . " no longer supports strings, pass an array", E_USER_NOTICE); } // do useful stuff with $param ... } ?></code>
通過錯誤到異常的轉換,無法測試是否對 $param
進行了有用的處理,因為當錯誤轉換為異常時,該代碼將永遠不會執行。
PHPUnit 行為的副作用
這種錯誤到異常的轉換會導致代碼在開發和測試中的行為與在生產環境中的行為有所不同。這是一個例子:
<code class="language-php"><?php error_reporting(E_ALL | E_STRICT); echo "Before warning\n"; trigger_error("Danger Will Robinson!", E_USER_WARNING); echo "After warning\n"; ?></code>
輸出:
<code>Before warning PHP Warning: Danger Will Robinson! in /home/matt/error_handler.php on line 4 After warning</code>
第一個 var_dump()
調用(在此期間,將錯誤轉換為異常的自定義錯誤處理程序正在生效)輸出 NULL。第二個 var_dump()
調用(在此期間,PHP 的默認錯誤處理程序正在生效)輸出有關已觸發錯誤的信息。請注意,這不是因為使用了自定義錯誤處理程序而導致第一個 var_dump()
調用輸出 NULL,而是因為該錯誤處理程序拋出了異常。如果此示例中顯示的錯誤處理程序沒有這樣做,則第一個 var_dump()
調用的輸出將與第二個相同。
解決方案
我們需要一個解決方案,該解決方案允許繼續執行正在測試的代碼,同時仍然允許我們檢查是否引發了錯誤條件。如上面的示例所示,允許代碼執行繼續可以使用不將錯誤轉換為異常的自定義錯誤處理程序來完成。此錯誤處理程序應該做的是捕獲錯誤信息,以便稍後使用斷言進行分析。這就是它的樣子:
<code class="language-php"><?php try { echo "Before exception\n"; throw new Exception("Danger Will Robinson!"); echo "After exception\n"; } catch (Exception $e) { echo "In catch block\n"; } ?></code>
setUp()
(在每個測試方法之前運行)處理設置錯誤處理程序,該處理程序只是同一類中的另一個方法,該方法將有關每個錯誤的信息存儲在一個數組中。然後,其他方法(如 assertError()
)由測試方法(如 testDoStuff()
)使用,以對該錯誤信息執行斷言並輸出相關的調試信息,例如與預期錯誤相比觸發的錯誤是什麼。其他有用的斷言類型包括邏輯反轉(即斷言未觸發特定錯誤)、檢查消息與正則表達式匹配的錯誤或檢查觸發的錯誤數量。
結論
如果您不關心測試觸發錯誤後的邏輯是否仍在執行,則 PHPUnit 的默認行為完全適合您的需求。但是,重要的是您要了解該行為的含義。如果您確實關心此類邏輯的執行,同樣重要的是您要知道如何補充 PHPUnit 的功能,以便在盡可能接近生產環境的條件下促進對代碼的準確測試。
圖片來自 Fotolia
(以下為FAQ,已根據原文內容調整格式和表達,並對部分問題進行了合併或簡化)
關於使用 PHPUnit 測試錯誤條件的常見問題解答 (FAQ)
Q1: 為什麼 PHPUnit 在控制台中沒有顯示任何錯誤?
PHPUnit 的設計方式允許有效測試錯誤和異常。如果您在控制台中沒有看到任何錯誤,則 PHPUnit 可能正在捕獲它們並將它們視為失敗的測試。要查看這些錯誤的詳細信息,可以在運行測試時使用 --debug
選項。這將提供更詳細的輸出,包括在測試期間捕獲的任何錯誤或異常。
Q2: 如何斷言 PHPUnit 中拋出了異常?
PHPUnit 提供了一組專門用於處理異常的斷言。最常用的是 expectException()
,您可以使用它來指定您期望拋出的異常類型。如果在測試期間拋出了指定的異常,則測試將通過。如果沒有,則測試將失敗。這允許您編寫專門檢查錯誤條件的正確處理的測試。
Q3: PHP 中的錯誤報告是如何工作的?
PHP 的錯誤報告功能允許您控制報告哪些錯誤以及如何處理它們。默認情況下,所有錯誤都會被報告並顯示。但是,您可以使用 error_reporting()
函數和 display_errors
ini 指令更改這些設置。這允許您隱藏某些類型的錯誤,或記錄錯誤而不是顯示它們。
Q4: 如何在 PHPUnit 中測試異常?
與Q2相同。
Q5: 如何為 PHPUnit 編寫測試?
為 PHPUnit 編寫測試涉及創建一個新的測試用例類,該類擴展 PHPUnitFrameworkTestCase 類。每個測試都是此類中的一個公共方法,以單詞“test”開頭。在每個測試方法內部,您可以使用 PHPUnit 的斷言來檢查您的代碼是否按預期運行。例如,您可以使用 assertEquals()
方法來檢查函數是否返回預期的結果。
Q6: 如何在 PHPUnit 中處理錯誤?
PHPUnit 提供了一組專門用於處理錯誤的斷言。最常用的是 expectError()
,您可以使用它來指定您期望觸發的錯誤類型。如果在測試期間觸發了指定的錯誤,則測試將通過。如果沒有,則測試將失敗。這允許您編寫專門檢查錯誤條件的正確處理的測試。
Q7: 如何調試 PHPUnit 中的測試?
PHPUnit 提供了幾個調試測試的選項。 --debug
選項提供更詳細的輸出,包括在測試期間捕獲的任何錯誤或異常。 --stop-on-error
、--stop-on-failure
和 --stop-on-risky
選項可用於在遇到某種類型的錯誤時停止測試運行。這可以使識別和修復問題更容易。
Q8: 如何在 PHPUnit 中測試錯誤條件?
PHPUnit 提供了幾種測試錯誤條件的方法。 expectError()
方法允許您指定您期望觸發的錯誤類型。 expectWarning()
方法允許您指定您期望觸發的警告類型。如果在測試期間觸發了指定的錯誤或警告,則測試將通過。如果沒有,則測試將失敗。
Q9: 如何在 PHPUnit 中處理警告?
PHPUnit 提供了一組專門用於處理警告的斷言。最常用的是 expectWarning()
,您可以使用它來指定您期望觸發的警告類型。如果在測試期間觸發了指定的警告,則測試將通過。如果沒有,則測試將失敗。這允許您編寫專門檢查警告條件的正確處理的測試。
Q10: 如何在 PHPUnit 中使用數據提供程序?
數據提供程序是 PHPUnit 的一個強大功能,允許您使用不同的數據集多次運行測試。要使用數據提供程序,您可以創建一個返回數組的數組的方法。每個內部數組都是測試的一組參數。然後,您使用 @dataProvider
註釋您的測試方法,後跟您的數據提供程序方法的名稱。然後,PHPUnit 將為每一組參數運行一次測試,並將參數傳遞給測試方法。
以上是PHP主|使用Phpunit測試錯誤條件的詳細內容。更多資訊請關注PHP中文網其他相關文章!