這邊先做個錯誤示範,以下的程式執行時,會因為對一個不存在的 array index 取值:
class Worker
{
public function work()
{
$arr = [];
$elem = $arr['nonExist'];
}
}
執行時會出現以下錯誤訊息:
PHP Notice: Undefined index: nonExist in /home/zero/tmp/phpunit/Worker.php
PHPUnit 執行 unit test 時會自動將 notice / warning 都轉成 exception,使用者變可以透過「@expectedException」來檢查確認是否有發生預期的錯誤:
class WorkerTest extends PHPUnit_Framework_TestCase
{
/**
* @expectedException PHPUnit_Framework_Error_Notice
*/
public function testWorker()
{
$worker = new Worker();
$worker->work();
}
}
unit test 執行結果:
zero@zero-lab:~/tmp/tests$ ./phpunit
PHPUnit 5.5-gc2e4cf1 by Sebastian Bergmann and contributors.
. 1 / 1 (100%)
Time: 202 ms, Memory: 3.00MB
但是當 array 取值前後加上了 try … catch 時會發生什麼事呢?
class Worker
{
public function work()
{
try {
$arr = [];
$elem = $arr['nonExist'];
} catch (Exception $e) {
// do something
}
}
}
再來執行一次 unit test:
zero@zero-lab:~/tmp/tests$ ./phpunit
PHPUnit 5.5-gc2e4cf1 by Sebastian Bergmann and contributors.
F 1 / 1 (100%)
Time: 27 ms, Memory: 3.00MB
There was 1 failure:
1) WorkerTest::testWorker
Failed asserting that exception of type "PHPUnit_Framework_Error_Notice" is thrown.
phpunit 顯示錯誤訊息,原本預期會收到「PHPUnit_Framework_Error_Notice」但現在確沒有收到,造成 assertion failed。
這時若在 catch 中將「$e」dump 出來,會發現 PHPUnit_Framework_Error_Notice 被程式中的 try … catch 抓到了:
object(PHPUnit_Framework_Error_Notice)#20 (8) {
....
}
個人覺得這個行為不是非常直覺,在正常行況下,PHP notice 不會被 try … catch 抓到,而會正常執行下去,但當執行測試時,卻會因為 phpunit 將 notice / warning 自動轉成 exceptions 而導致程式的 work flow 與原先的設計不同,並造成測試時的警報。
目前還沒有想到什麼方法可以避開這個問題,若真要解決這個問題的話,最好的辦法,應該還是在實作時就避免出現 PHP notice 或 warning。