PHPUnitでエラーをトリガーするメソッドの戻り値をテストします
-
22-07-2019 - |
質問
この質問は、PHPUnitの使用に固有のものです。
PHPUnitは、PHPエラーを自動的に例外に変換します。 PHPエラー( trigger_error による組み込みエラーまたはユーザー生成エラー)をトリガーするメソッドの戻り値をテストする方法はありますか?
テストするコードの例:
function load_file ($file)
{
if (! file_exists($file)) {
trigger_error("file {$file} does not exist", E_USER_WARNING);
return false;
}
return file_get_contents($file);
}
これは私が書きたいタイプのテストです:
public function testLoadFile ()
{
$this->assertFalse(load_file('/some/non-existent/file'));
}
私が抱えている問題は、トリガーされたエラーが原因でユニットテストが失敗することです(そうするべきです)。しかし、それをキャッチしようとしたり、予期される例外を設定しようとすると、エラーがトリガーされた後にコードが実行されることはないため、メソッドの戻り値をテストする方法はありません。
この例は機能しません:
public function testLoadFile ()
{
$this->setExpectedException('Exception');
$result = load_file('/some/non-existent/file');
// code after this point never gets executed
$this->assertFalse($result);
}
これを達成する方法はありますか?
解決
1つの単体テスト内でこれを行う方法はありません。戻り値のテストと通知を2つの異なるテストに分割すると可能です。
PHPUnitのエラーハンドラーは、PHPエラーと通知をキャッチし、例外に変換します。これは、定義によりプログラムの実行を停止します。テストしている関数はまったく戻りません。ただし、実行時であっても、エラーから例外への変換を一時的に無効にすることができます。
これは例の方がおそらく簡単なので、2つのテストは次のようになります。
public function testLoadFileTriggersErrorWhenFileNotFound()
{
$this->setExpectedException('PHPUnit_Framework_Error_Warning'); // Or whichever exception it is
$result = load_file('/some/non-existent/file');
}
public function testLoadFileRetunsFalseWhenFileNotFound()
{
PHPUnit_Framework_Error_Warning::$enabled = FALSE;
$result = load_file('/some/non-existent/file');
$this->assertFalse($result);
}
これには、テストをより明確に、よりクリーンに、自己文書化できるという追加のボーナスもあります。
再:コメント: それは素晴らしい質問であり、2、3のテストを実行するまでは分かりませんでした。少なくともPHPUnit 3.3.17(現在の安定版リリース)の時点で、デフォルト/元の値を復元しない ように見えます。
そのため、実際には上記を次のように修正します。
public function testLoadFileRetunsFalseWhenFileNotFound()
{
$warningEnabledOrig = PHPUnit_Framework_Error_Warning::$enabled;
PHPUnit_Framework_Error_Warning::$enabled = false;
$result = load_file('/some/non-existent/file');
$this->assertFalse($result);
PHPUnit_Framework_Error_Warning::$enabled = $warningEnabledOrig;
}
再:2番目のコメント:
それは完全に真実ではありません。私はPHPUnitのエラーハンドラを調べていますが、次のように機能します。
-
E_WARNING
の場合、例外クラスとしてPHPUnit_Framework_Error_Warning
を使用します。 -
E_NOTICE
またはE_STRICT
エラーの場合、PHPUnit_Framework_Error_Notice
を使用します
- その他、例外クラスとして
PHPUnit_Framework_Error
を使用します。
したがって、はい、 E_USER _ *
のエラーはPHPUnitの* _Warningまたは* _Noticeクラスに変換されません。それらは一般的な PHPUnit_Framework_Error
例外に変換されます。
さらなる思考
関数の使用方法に厳密に依存しますが、私であれば、おそらくエラーをトリガーする代わりに実際の例外をスローするように切り替えます。はい。これにより、メソッドのロジックフローが変更され、メソッドを使用するコードが変更されます。ファイルを読み取れないときに実行が停止することはありません。しかし、要求されたファイルが存在しないかどうかは、本当に例外的の動作であるかどうかを判断するのはあなた次第です。エラー/警告/通知よりも例外を使用する傾向があります。例外を使用すると、アプリケーションフローの処理、テスト、および作業が容易になります。私は通常、減価償却されたメソッド呼び出しなどのために通知を予約します。
他のヒント
phpunit.xml
構成ファイルを使用して、notice / warning / error to Exception変換を無効にします。 マニュアルの詳細。基本的には次のようなものです:
<phpunit convertErrorsToExceptions="false"
convertNoticesToExceptions="false"
convertWarningsToExceptions="false">
</phpunit>
一般的な&quot; Exception
&quot;を期待する代わりに、&quot; PHPUnit_Framework_Error
&quot;を期待するのはどうでしょうか。
次のようなことが起こる可能性があります:
/**
* @expectedException PHPUnit_Framework_Error
*/
public function testFailingInclude()
{
include 'not_existing_file.php';
}
これは次のようにも書かれていると思います:
public function testLoadFile ()
{
$this->setExpectedException('PHPUnit_Framework_Error');
$result = load_file('/some/non-existent/file');
// code after this point never gets executed
$this->assertFalse($result);
}
詳細については、 PHPエラーのテスト
特に、(引用)と書かれています:
PHPUnit_Framework_Error_Notice
およびPHPUnit_Framework_Error_Warning
は PHPの注意と警告はそれぞれ。
システムにある/usr/share/php/PHPUnit/TextUI/TestRunner.phpファイルを見ると、この(198行目以降)が表示されています:
if (!$arguments['convertNoticesToExceptions']) {
PHPUnit_Framework_Error_Notice::$enabled = FALSE;
}
if (!$arguments['convertWarningsToExceptions']) {
PHPUnit_Framework_Error_Warning::$enabled = FALSE;
}
そのため、その動作を有効にするために何らかのパラメーターを渡す必要があるかもしれません。ただし、デフォルトで有効になっているようです...
実際には、戻り値とスローされた例外(この場合はPHPUnitによって変換されたエラー)の両方をテストする方法があります。
次の操作を行うだけです。
public function testLoadFileTriggersErrorWhenFileNotFound()
{
$this->assertFalse(@load_file('/some/non-existent/file'));
$this->setExpectedException('PHPUnit_Framework_Error_Warning'); // Or whichever exception it is
load_file('/some/non-existent/file');
}
戻り値をテストするには、関数呼び出しでエラー抑制演算子を使用する必要があることに注意してください(関数名の前の @
)。これにより、例外がスローされず、実行が継続されます。その後、通常どおりエラーをテストするために予期される例外を設定する必要があります。
できないのは、単体テスト内で複数の例外をテストすることです。