17

最近刚进入 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;
    }   
}

现在我如何测试学生类是否返回具有值集的对象数组并检查使用学生类的getter的值

请务必抛出一些光/信息/链接,以引导我走上正确的道路。

谢谢

4

3 回答 3

37

我在下面写了一些示例代码;我猜参数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());
    }
}

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

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

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

于 2013-06-25T00:18:22.843 回答
28

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

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

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

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

于 2014-01-30T17:16:07.083 回答
5

你可以用断言来做到这一点。首先你应该获得一个实际的结果,然后用它做一些断言。比较:

您可以断言它是一个数组:

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 编写测试,它也应该提供所有断言的列表。

于 2013-06-24T22:26:24.370 回答