2009-05-22 13 views
28

私は主に単体テストのメリットを確信しています。この概念をPHPで書かれた大きな既存のコードベースに適用したいと思います。このコードの10%未満がオブジェクト指向です。手続き型コードベースでPHPで単体テストを書くにはどうしたらいいですか?

私はいくつかのユニットテストフレームワーク(PHPUnit、SimpleTest、phpt)を見てきました。しかし、私はプロシージャコードをテストするこれらのサンプルの例は見つけていません。私の状況に最適なフレームワークは何ですか?非OOPコードを使用した単体テストPHPの例はありますか?

答えて

34

手続き型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を返すかによって機能するかどうかです。最初のケースでは、テストは簡単ですが、やはり、それは両方のケースで可能です:あなたのコードは副作用によって動作し、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); 
} 

、あなたはまだかなり簡単にテストすることができます:

/* 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); 
    } 

これが役立ちます。

+0

あなたがテストしているコードが 'exit;'ステートメントで分かれていればこれはうまくいかない: –

+3

@ YarekT 'exit'や' die'ステートメントでコードが散らばっていれば、テストはうまくいっていない可能性があります。予想されるスクリプトの終了を処理するには、例外をスローし、発生したときにカスタム例外の型を無視できるようにスマートなカスタム例外ハンドラを登録します。次に、期待される例外がスローされることをテストできます。とにかくブートストラップ段階の後に「終了」または「死ぬ」必要があります。 – rdlowrey

1

あなたは

require_once 'your_non_oop_file.php' # Contains fct_to_test() 

そして、あなたはあなたのテスト関数を定義PHPUnitでを使用してテストクラスにあなたの非OOPのコードを含めるように試みることができる:

テストはうまくやって何単位
testfct_to_test() { 
    assertEquals(result_expected, fct_to_test(), 'Fail with fct_to_test'); 
} 
+0

これは興味深い解決策のように見えますが、ほとんどのロジックが機能を含まず、単純なループと条件付きであればどうでしょうか? –

+5

それから、スパゲッティコードの助けになりました。 –

+0

私はTravisがhtmlでPHPコードを持っていないと仮定しました。 –

6

、そしてどのようないくつかの入力を与えるコードを持っていて、いくつかの出力を取り戻すことを期待しています。後で機能を追加すると、テストを実行して、同じ方法で古い機能を実行していることを確認できます。

あなたは手続き型のコードベースを持っているのであれば、あなたは、PHPのコードベースでこのトリック試験方法

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ファイルである場合は、運が悪いです。あなたのコードは、別々のユニットに分けることはできません。つまり、ユニットテストはあまり役に立たないでしょう。あなたはSeleniumWatirのような製品を使って "受け入れテスト"レベルで時間を過ごす方が良いでしょう。これらはブラウザを自動化してから、特定の場所/フォームとしてコンテンツのページをチェックします。

+0

自分のコードを明確に別の単位に分けることができます。あなたの例は有望に見えますが、これは特定のフレームワークを使用していないと思いますか? –

+0

擬似テストコードですが、実際のSImpleTestテストとPHPUnitテストは非常によく似ています。 –

関連する問題