【问题标题】:PHPUnit: Test array of objectsPHPUnit:测试对象数组
【发布时间】:2013-06-21 02:56:36
【问题描述】:

最近刚接触 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 类是否返回一个设置了值的对象数组,并使用 Student

的 getter 检查值

请务必提供一些指引我正确路径的光线/信息/链接。

谢谢

【问题讨论】:

    标签: php unit-testing phpunit


    【解决方案1】:

    我在下面写了一些示例代码;我猜getStudents 的参数是可选过滤器。我们有一项测试可以吸引所有学生。我不知道他们是否总是按排序顺序返回,这就是为什么我不在 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());
        }
    }
    

    这是很好的第一步。使用一段时间后,您会发现它非常脆弱。 IE。第一次考试必须有 7 名学生才能通过。必须只有一个叫 Bob 的学生才能通过第二个学生。如果您的\OldStudents::getStudentByName 正在从数据库中获取数据,它也会很慢;我们希望单元测试尽可能快地运行。

    解决这两个问题的方法是模拟对\OldStudents::getStudentByName 的调用。然后您可以注入您自己的人工数据,然后您将只测试getAllStudents 中的逻辑。这反过来意味着当您的单元测试中断时,您可能会中断它的只有 20 行左右,而不是 1000 行。

    究竟如何进行模拟完全是另一个问题,可能取决于 PHP 版本,以及您的代码设置有多灵活。 (“OldStudents”听起来你正在处理遗留代码,也许你无法触及它。)

    【讨论】:

    • 嗨,Darren,你对“OldStudents”的看法是完全正确的,它确实是遗留代码,我无法触及它。感谢您的示例代码。我正在修复我想要投票的答案,因为你们都给出了令人满意的答复:)
    【解决方案2】:

    PHPUnit 从 3.1.4 版开始具有断言“assertContainsOnly”,参数“type”可以断言任何 PHP 类型(包括实例和内部类型),并且至少在 3.7 版中具有断言“assertContainsOnlyInstancesOf”,它仅显式检查类实例,而不是 PHP 变量类型。

    因此,检查数组是否仅包含给定类型的对象的测试很简单:

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

    请注意,此检查隐式测试 $students 是数组还是实现 Traversable 接口的对象。实现 Traversable 并不意味着你可以计数,所以之后调用assertCount 来断言存在给定数量的Student 对象并不能保证成功,但是添加的返回值实际上是一个数组的检查似乎太臃肿了给我这里。您正在创建并返回一个包含某些内容的数组 - 假设您可以计算它是安全的。但这可能并非所有地方都是如此。

    【讨论】:

    • 函数其实是assertContainsOnlyInstancesOf()(实例应该是复数)。
    • 感谢您发现那个错字 - 自动补全的懒惰当时可能打击了我。随意在 SO 上自己编辑这些错别字。他们将进入队列并接受审查,原始作者将收到通知。这样更容易更新不正确的信息。
    • 我试过了,但因为我只更改了两个字符,它不会接受它;)
    • 在我看来,assertContainsOnlyInstancesOf() 比其他人要好得多。
    【解决方案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 编写测试,它也应该提供所有断言的列表。

    【讨论】:

    猜你喜欢
    • 2020-06-08
    • 2021-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-11
    • 2013-12-06
    • 2017-02-17
    • 2023-03-06
    相关资源
    最近更新 更多