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

Теперь, как я могу проверить, возвращает ли класс Студенты массив объектов с установленными значениями и проверяет значения с использованием геттеров от Студент Класс

Пожалуйста, бросьте какой-то свет/информацию/ссылки, которые направляют меня на правильный путь.

Спасибо

Ответ 1

Я написал пример кода ниже; Я предположил, что параметры getStudents были необязательными фильтрами. У нас есть один тест, который получает все студенты. Я не знаю, всегда ли они возвращаются в отсортированном порядке, поэтому я больше ничего не проверяю в классе учеников. Второй тест получает одного конкретного ученика и начинает тестировать некоторые свойства ученика.

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 учеников, чтобы пройти первый тест. Должен быть ровно один студент по имени Боб, чтобы пройти второй. Если ваш \OldStudents::getStudentByName получает данные из базы данных, он также будет медленным; мы хотим, чтобы модульные тесты выполнялись как можно быстрее.

Исправление для обоих из них состоит в том, чтобы посмеяться над вызовом \OldStudents::getStudentByName. Затем вы можете ввести свои собственные искусственные данные, и тогда вы будете только проверять логику в getAllStudents. Это, в свою очередь, означает, что при перерывах в модульном тесте есть только около 20 строк, где вы могли бы его разорвать, а не 1000.

Вопрос о том, как выполнять макет, - это совершенно другой вопрос, и он может зависеть от версии PHP и от того, насколько гибок ваш код. ("OldStudents" звучит так, как будто вы имеете дело с устаревшим кодом, и, возможно, вы не можете его коснуться).

Ответ 2

PHPUnit, поскольку версия 3.1.4 имеет утверждение "assertContainsOnly" с параметром "type", который может утверждать любой тип PHP (включая экземпляры и внутренние типы), и, по крайней мере, в версии 3.7 есть утверждение "assertContainsOnlyInstancesOf", которое явно только проверяет экземпляры класса, а не типы переменных PHP.

Таким образом, проверка теста, если массив содержит только объекты данного типа, просто:

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

Обратите внимание, что эта проверка неявно проверяет, что $students является либо массивом, либо объектом, реализующим интерфейс Traversable. Внедрение Traversable не означает, что вы можете рассчитывать, поэтому вызов assertCount после этого, чтобы утверждать, что количество объектов Student присутствует, не гарантируется, что оно будет успешным, но добавленная проверка, что возвращаемое значение на самом деле является массивом, кажется слишком много раздутым мне здесь. Вы создаете и возвращаете массив с чем-то в нем - можно с уверенностью предположить, что вы можете считать его. Но это может быть не везде.

Ответ 3

Вы можете сделать это с утверждениями. Прежде всего вы должны получить реальный результат, а затем сделать некоторые утверждения с ним. Для сравнения:

Вы можете утверждать, что это массив:

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 для написания своего теста, он также должен предложить список всех утверждений.