2013-06-24 16 views
10

Ich bin erst kürzlich in PHPUnit gesprungen, habe etwas darüber gelesen und einige Beispiele ausprobiert, um mich mit den Tests für meine zukünftigen Projekte vertraut zu machen.PHPUnit: Testarray von Objekten

ich dieses Szenario testen müssen, habe ich Schüler der Klasse, die wie folgt lautet:

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; 
    } 
} 

und der Schüler der Klasse

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; 
    } 
} 

Nun, wie kann ich, ob die Students Klasse kehrt testen ein Array von Objekten mit den eingestellten Werten und überprüfen Sie die Werte mit den Gettern von Student Klasse

Bitte werfen Sie ein paar Licht/Informationen/Links, die mich in den richtigen Pfad führt.

Dank

Antwort

24

Ich habe einen Beispielcode unten geschrieben; Ich vermutete, dass die Parameter getStudents optionale Filter waren. Wir haben einen Test, der alle Schüler bekommt. Ich weiß nicht, ob sie immer in sortierter Reihenfolge zurückkommen, weshalb ich in der Studentenklasse nichts anderes teste. Der zweite Test erhält einen bestimmten Schüler und beginnt mit dem Testen einiger Schülereigenschaften.

class StudentsTest extends PHPUnit_Framework_TestCase{ 

    public function testGetAllStudents(){ 
     $s=new Students; 
     $students=$s->getStudents("",""); 
     $this->assertInternalType('array',$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->assertInternalType('array',$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()); 
    } 
} 

Dies ist ein guter erster Schritt. Nachdem Sie es eine Weile benutzt haben, werden Sie feststellen, dass es ziemlich zerbrechlich ist. I.e. Sie müssen genau 7 Schüler haben, damit der erste Test bestanden wird. Es muss genau einen Studenten namens Bob geben, damit der zweite vorbeikommt. Wenn Ihr \OldStudents::getStudentByName Daten von einer Datenbank erhält, wird es auch langsam sein; Wir möchten, dass Komponententests so schnell wie möglich ablaufen.

Die Lösung für beide ist, den Anruf zu \OldStudents::getStudentByName zu verspotten. Dann können Sie Ihre eigenen künstlichen Daten injizieren, und dann testen Sie nur die Logik in getAllStudents. Das bedeutet wiederum, dass wenn der Komponententest unterbrochen wird, es nur 20 oder mehr Linien gibt, an denen man hätte brechen können, nicht 1000.

Genau, wie man das Mocking macht, ist eine ganze 'nother Frage und könnte von der PHP-Version abhängen, und wie flexibel Ihr Code-Setup ist. ("OldStudents" hört sich so an, als ob Sie mit altem Code arbeiten und vielleicht können Sie ihn nicht anfassen.)

+0

Hallo Darren, du hast absolut Recht mit "OldStudents" ist es in der Tat Legacy-Code und ich kann es nicht berühren. Danke für deinen Beispielcode. Ich bin in einem Fix, auf die ich antworten möchte, wie Sie beide befriedigende Antworten gaben :) – 125369

+1

Nun, Sie gewinnen es !!! – 125369

3

Sie können mit Behauptungen tun. Zuallererst sollten Sie ein tatsächliches Ergebnis erwerben, dann einige Behauptungen damit machen. Vergleichen:

können Sie behaupten, dass es ein Array ist:

class InternalTypeTest extends PHPUnit_Framework_TestCase 
{ 
    public function testFailure() 
    { 
     $this->assertInternalType('array', 42); 
    } 
} 

Dann könnte man behaupten, dass es nicht leer ist (wie Sie es wissen müssen einige Daten zurückgeben) :

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

Und dann können Sie behaupten, dass jeder Wert von Ihnen ist Studententyp:

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

Ich hoffe, das gibt Ihnen einige Hinweise. Unter dem obigen Link finden Sie eine Liste häufiger Assertionen. Wenn Sie eine IDE verwenden, um Ihren Test zu schreiben, sollte es eine Liste aller Behauptungen auch anbieten.

10

PHPUnit seit Version 3.1.4 hat die Assertion "assertContainsOnly" mit dem Parameter "type", die jeden PHP - Typ (einschließlich Instanzen und interne Typen), und mindestens Version 3.7 hat die Assertion "assertContainsOnlyInstancesOf", die explizit nur nach Klasseninstanzen sucht, nicht nach PHP-Variablentypen.

So überprüft der Test, ob ein Array nur Objekte eines bestimmten Typs enthält, ist einfach:

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

Beachten Sie, dass diese Prüfung testet implizit, dass $students ist entweder ein Array oder ein Objekt die Travers Schnittstelle implementiert. Das Implementieren von Traversable bedeutet nicht, dass Sie zählen können. Daher ist das Aufrufen von assertCount danach, eine gegebene Anzahl von Student Objekten beizubehalten, nicht garantiert, um erfolgreich zu sein, aber die hinzugefügte Überprüfung, dass der Rückgabewert tatsächlich ein Array ist, scheint mir hier zu viel aufgebläht. Sie erstellen und geben ein Array mit etwas zurück - es ist davon auszugehen, dass Sie es zählen können. Aber das ist vielleicht nicht überall der Fall.

+0

Die Funktion ist tatsächlich 'assertContainsOnlyInstancesOf()' (Instanzen sollten im Plural sein). – kielabokkie

+0

Danke, dass du diesen Tippfehler entdeckt hast - die Faulheit der Autovervollständigung hat mich dann wohl getroffen. Fühlen Sie sich frei, solche Tippfehler selbst hier auf SO zu bearbeiten. Sie werden in eine Warteschlange eingereiht und überprüft, und der ursprüngliche Autor wird benachrichtigt. Auf diese Weise ist es einfacher, falsche Informationen zu aktualisieren. – Sven

+0

Ich versuchte das, aber weil ich nur zwei Zeichen änderte, würde es es nicht akzeptieren;) – kielabokkie