私は単体テストの利点についてほぼ確信しており、PHP で書かれた既存の大規模なコードベースにこの概念を適用したいと考えています。このコードの 10% 未満はオブジェクト指向です。
いくつかの単体テスト フレームワーク (PHPUnit、SimpleTest、および phpt) を見てきました。ただし、手続き型コードをテストするこれらの例は見つかりませんでした。私の状況に最適なフレームワークは何ですか? 非 OOP コードを使用して PHP の単体テストを行う例はありますか?
私は単体テストの利点についてほぼ確信しており、PHP で書かれた既存の大規模なコードベースにこの概念を適用したいと考えています。このコードの 10% 未満はオブジェクト指向です。
いくつかの単体テスト フレームワーク (PHPUnit、SimpleTest、および phpt) を見てきました。ただし、手続き型コードをテストするこれらの例は見つかりませんでした。私の状況に最適なフレームワークは何ですか? 非 OOP コードを使用して PHP の単体テストを行う例はありますか?
手続き型 PHP を単体テストできますが、問題ありません。また、コードが HTML と混ざっていても、決して運が悪いわけではありません。
アプリケーションまたは受け入れテストのレベルでは、手続き型 PHP はおそらくスーパーグローバル ( など) の値に依存して$_POST, $_GET, $_COOKIE
動作を決定し、テンプレート ファイルを含めて出力を吐き出します。
アプリケーション レベルのテストを行うには、スーパーグローバル値を設定するだけです。出力バッファーを開始します (大量の html が画面にあふれないようにするため); ページを呼び出します。バッファー内のものに対してアサートします。最後にバッファを破棄します。したがって、次のようなことができます。
public function setUp()
{
if (isset($_POST['foo'])) {
unset($_POST['foo']);
}
}
public function testSomeKindOfAcceptanceTest()
{
$_POST['foo'] = 'bar';
ob_start();
include('fileToTest.php');
$output = ob_get_flush();
$this->assertContains($someExpectedString, $output);
}
多くのインクルードを含む巨大な「フレームワーク」の場合でも、この種のテストにより、アプリケーション レベルの機能が機能しているかどうかがわかります。これは、コードの改善を開始する際に非常に重要になります。なぜなら、データベース コネクタがまだ機能し、以前よりも見栄えが良いと確信している場合でも、ボタンをクリックして、はい、まだできることを確認したくなるからです。データベースを介してログインおよびログアウトします。
下位レベルでは、変数のスコープと、関数が副作用 (true または false を返す) によって機能するか、結果を直接返すかによって、わずかな違いがあります。
変数は、関数間でパラメーターまたはパラメーターの配列として明示的に渡されますか? それとも、変数はさまざまな場所に設定され、グローバルとして暗黙的に渡されますか? (良い) 明示的なケースである場合は、(1) 関数を保持するファイルを含め、(2) 関数テスト値を直接入力し、(3) 出力をキャプチャしてそれに対してアサートすることにより、関数を単体テストできます。グローバルを使用している場合は、(上記の $_POST の例のように) テスト間ですべてのグローバルを慎重に無効にするように特に注意する必要があります。多くのグローバルをプッシュおよびプルする関数を扱う場合、テストを非常に小さく保つことも特に役立ちます (5 ~ 10 行、1 ~ 2 アサート)。
もう 1 つの基本的な問題は、関数が出力を返すことによって機能するか、渡されたパラメーターを変更して代わりに true/false を返すことによって機能するかです。最初のケースでは、テストはより簡単ですが、繰り返しますが、両方のケースで可能です:
// assuming you required the file of interest at the top of the test file
public function testShouldConcatenateTwoStringsAndReturnResult()
{
$stringOne = 'foo';
$stringTwo = 'bar';
$expectedOutput = 'foobar';
$output = myCustomCatFunction($stringOne, $stringTwo);
$this->assertEquals($expectedOutput, $output);
}
コードが副作用によって機能し、true または false を返す悪いケースでも、非常に簡単にテストできます。
/* suppose your cat function stupidly
* overwrites the first parameter
* with the result of concatenation,
* as an admittedly contrived example
*/
public function testShouldConcatenateTwoStringsAndReturnTrue()
{
$stringOne = 'foo';
$stringTwo = 'bar';
$expectedOutput = 'foobar';
$output = myCustomCatFunction($stringOne, $stringTwo);
$this->assertTrue($output);
$this->Equals($expectedOutput, $stringOne);
}
お役に立てれば。
単体テストがうまく機能し、それらを使用する必要があるのは、いくつかの入力を与えるコード片があり、いくつかの出力が返されることを期待している場合です。後で機能を追加するときに、テストを実行して、古い機能を同じように実行していることを確認できます。
したがって、手続き型のコードベースがある場合は、テスト メソッドで関数を呼び出してこれを実現できます。
require 'my-libraries.php';
class SomeTest extends SomeBaseTestFromSomeFramework {
public function testSetup() {
$this->assertTrue(true);
}
public function testMyFunction() {
$output = my_function('foo',3);
$this->assertEquals('expected output',$output);
}
}
コードベースとテスト フレームワークには、Web ブラウザー (セッション、共有グローバル変数など)。ライブラリ コードをインクルードして簡単なテスト (上記の testSetup 関数) を実行できるようになるまで、ある程度の時間を費やすことを期待してください。
コードに関数がなく、HTML ページを出力する単なる一連の PHP ファイルである場合は、運が悪いと言えます。コードを個別のユニットに分割することはできません。つまり、ユニット テストはあまり役に立ちません。SeleniumやWatirなどの製品を使用して、「受け入れテスト」レベルで時間を費やす方がよいでしょう。これらにより、ブラウザを自動化し、ページのコンテンツを特定の場所/フォームでチェックできます。
を使用して、非 oop コードをテスト クラスに含めることができます。
require_once 'your_non_oop_file.php' # Contains fct_to_test()
phpUnit を使用して、テスト関数を定義します。
testfct_to_test() {
assertEquals( result_expected, fct_to_test(), 'Fail with fct_to_test' );
}