web-dev-qa-db-ja.com

PHPUnit:オブジェクトの配列をテストする

最近PHPUnitに飛び込んだばかりですが、将来のプロジェクトのテストを書きやすくするために、いくつかの例を試して、PHPUnitについて読んでいます。

このシナリオをテストする必要があります。次のような学生クラスがあります。

class Students
{
    public function getStudents($studentName, $studentId)
    {       
        $students= array();

        //Instantiating OldStudent Class from Old Project
        $oldStudents = \OldStudents::getStudentByName($studentName, $studentId);

        //Create a Student Object for every OldStudent found on Old Project and set
        //values
        foreach ($oldStudents as $oldStudent)
        {            
            $student = new \Entity\Student();

            //Set Student ID
            $student->setStudentId($oldStudent->getStudentID());

            //Set Student Name
            $student->setStudentName($oldStudent->getStudentName());    
           //.....other setters for student data, irrelevant for this example 

            $students[] = $student;            
        }

        return $students;
    }
}

そして学生クラス

Class Student
{
    protected $studentId;
    protected $studentName;

    public function getStudentId()
    {
        return $this->studentId;
    }
    public function setStudentId($studentId)
    {
        $this->studentId = $studentId;
        return $this;
    }
    public function getStudentName()
    {
        return $this->studentName;
    }
    public function setStudentName($studentName)
    {
        $this->studentName = $studentName;
        return $this;
    }   
}

Students Classが値が設定されたオブジェクトの配列を返すかどうかをテストし、値がStudent Classのゲッターを使用しているかどうかを確認するにはどうすればよいですか?

私に正しい道を案内する光/情報/リンクを投げてください。

ありがとう

15
125369

以下のコード例をいくつか書きました。 getStudentsへのパラメーターはオプションのフィルターだと思いました。すべての学生を対象とする1つのテストがあります。それらが常に並べ替えられた順序で返されるかどうかはわかりません。そのため、Studentクラスでは何もテストしません。 2番目のテストでは、特定の生徒を1人取得し、生徒のプロパティのいくつかのテストを開始します。

class StudentsTest extends PHPUnit_Framework_TestCase{

    public function testGetAllStudents(){
        $s=new Students;
        $students=$s->getStudents("","");
        $this->assertIsArray($students);
        $this->assertEquals(7,count($students));
        $first=$students[0];    //Previous assert tells us this is safe
        $this->assertInstanceOf('Student',$first);
    }

    public function testGetOnlyStudentNamedBob(){
        $s=new Students;
        $students=$s->getStudents("Bob","");
        $this->assertIsArray($students);
        $this->assertEquals(1,count($students));
        $first=$students[0];    //Previous assert tells us this is safe
        $this->assertInstanceOf('Student',$first);
        $this->assertEquals('Bob',$first->getStudentName());
    }
}

これは良い第一歩です。しばらく使ってみると、かなり壊れやすいことに気づくでしょう。つまり最初のテストに合格するには、ちょうど7人の生徒が必要です。 2人目が合格するには、ボブという生徒が1人だけいる必要があります。 \OldStudents::getStudentByNameがデータベースからデータを取得している場合も、速度が遅くなります。ユニットテストをできるだけ速く実行したいです。

これら両方の修正は、\OldStudents::getStudentByNameへの呼び出しを模擬することです。その後、独自の人工データを注入できます。その後、getAllStudentsのロジックのみをテストします。つまり、単体テストが壊れた場合、それを壊した可能性があるのは1000行ではなく、20行程度しかありません。

モックを行う正確な方法はまったく別の問題であり、PHPバージョン、およびコードセットアップの柔軟性に依存する可能性があります。( "OldStudents"は、レガシーコードと触れられないかもしれません。)

31
Darren Cook

バージョン3.1.4以降のPHPUnitには、任意のPHP=タイプ(インスタンスと内部タイプを含む))を表明できるパラメータ「type」を含むアサーション「assertContainsOnly」があり、少なくともバージョン3.7ではアサーションがあります"assertContainsOnlyInstancesOf"は、クラスのインスタンスのみを明示的にチェックします。PHP変数の型ではありません。

したがって、配列に特定のタイプのオブジェクトのみが含まれているかどうかを確認するテストは、次のようになります。

$this->assertContainsOnlyInstancesOf('Student', $students);

このチェックは、$studentsが配列またはTraversableインターフェイスを実装するオブジェクトであることを暗黙的にテストすることに注意してください。 Traversableを実装してもカウントできるわけではないので、後でassertCountを呼び出して特定の数のStudentオブジェクトが存在することをアサートするとは限りませんが、戻り値が実際に配列はここでは私には大きすぎるようです。何かを含む配列を作成して返します-数えることができると仮定しても安全です。しかし、これはどこでも当てはまるとは限りません。

23
Sven

あなたはアサーションでそれを行うことができます。まず最初にactual結果を取得してから、それを使用してアサーションを実行する必要があります。比較:

あなたはそれが配列であることを主張することができます:

class InternalTypeTest extends PHPUnit_Framework_TestCase
{
    public function testFailure()
    {
        $this->assertInternalType('array', 42);
        # Phpunit 7.5+: $this->assertIsArray(42);
    }
}

次に、それが空ではないと断言できます(ご存知のように、データを返す必要があります)。

class NotEmptyTest extends PHPUnit_Framework_TestCase
{
    public function testFailure()
    {
        $this->assertNotEmpty(ARRAY());
    }
}

そして、あなたはそれぞれの値があなたの学生タイプであると主張することができます:

class InstanceOfTest extends PHPUnit_Framework_TestCase
{
    public function testFailure()
    {
        $this->assertInstanceOf('Student', new Exception);
    }
}

これがあなたにいくつかの指針を与えることを願っています。一般的なアサーションのリストについては、上記のリンクを参照してください。テストを書くためにIDEを使用する場合、すべてのアサーションのリストも提供するはずです。

3
hakre