web-dev-qa-db-fra.com

PHPUnit: test de tableau d'objets

Je viens de sauter dans PHPUnit récemment, j'ai lu des trucs à ce sujet, essayé quelques exemples, afin de me familiariser avec l'écriture des tests pour mes futurs projets.

J'ai besoin de tester ce scénario, j'ai une classe d'étudiants qui ressemble à ceci:

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

Et la classe étudiante

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

Maintenant, comment puis-je tester si la classe Students renvoie un tableau d'objets avec les valeurs définies et vérifier les valeurs en utilisant les getters de Student Class

S'il vous plaît jetez un peu de lumière/informations/liens selon ce qui me dirige dans le bon chemin.

Merci

15
125369

J'ai écrit un exemple de code ci-dessous; J'ai deviné que les paramètres de getStudents étaient des filtres facultatifs. Nous avons un test qui obtient tous les étudiants. Je ne sais pas s'ils reviennent toujours dans l'ordre trié, c'est pourquoi je ne teste rien d'autre en classe Élève. Le deuxième test obtient un étudiant particulier et commence à tester certaines des propriétés Student.

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

C'est une bonne première étape. Après l'avoir utilisé pendant un certain temps, vous vous rendrez compte qu'il est assez fragile. C'est à dire. vous devez avoir exactement 7 étudiants pour réussir le premier test. Il doit y avoir exactement un élève appelé Bob pour que le second passe. Si ton \OldStudents::getStudentByName obtient des données d'une base de données, cela sera également lent; nous voulons que les tests unitaires s'exécutent le plus rapidement possible.

La solution pour les deux est de se moquer de l'appel à \OldStudents::getStudentByName. Ensuite, vous pouvez injecter vos propres données artificielles, puis vous testerez uniquement la logique dans getAllStudents. Ce qui signifie que lorsque votre test unitaire échoue, il n'y a que 20 lignes environ où vous auriez pu le casser, pas des milliers.

La façon exacte de se moquer est une toute autre question, et pourrait dépendre de PHP version, et de la flexibilité de votre configuration de code. ("OldStudents" sonne comme si vous traitez avec du code hérité et vous ne pouvez peut-être pas y toucher.)

31
Darren Cook

PHPUnit depuis la version 3.1.4 a l'assertion "assertContainsOnly" avec le paramètre "type" qui peut affirmer n'importe quel type PHP (y compris les instances et les types internes), et dans au moins la version 3.7 a l'assertion "assertContainsOnlyInstancesOf" qui vérifie explicitement uniquement les instances de classe, pas PHP types de variables.

Ainsi, le test de vérification si un tableau ne contient que des objets d'un type donné est simplement:

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

Notez que cette vérification teste implicitement que $students est soit un tableau, soit un objet implémentant l'interface Traversable. L'implémentation de Traversable ne signifie pas que vous pouvez compter, donc appeler par la suite assertCount pour affirmer qu'un certain nombre d'objets Student est présent n'est pas garanti pour réussir, mais la vérification supplémentaire que la valeur de retour est en fait un tableau me semble trop gonflé ici. Vous créez et renvoyez un tableau contenant quelque chose - il est sûr de supposer que vous pouvez le compter. Mais cela pourrait ne pas être le cas partout.

23
Sven

Vous pouvez le faire avec des assertions. Tout d'abord, vous devez acquérir un résultat réel , puis faire quelques assertions avec. Comparer:

Vous pouvez affirmer qu'il s'agit d'un tableau:

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

Ensuite, vous pouvez affirmer qu'il n'est pas vide (comme vous le savez, il doit renvoyer des données):

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

Et puis vous pouvez affirmer que chaque valeur est de votre type d'élève:

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

J'espère que cela vous donne quelques conseils. Voir le lien ci-dessus pour une liste des assertions courantes. Si vous utilisez un IDE pour écrire votre test, il devrait également offrir une liste de toutes les assertions.

3
hakre