php PHPUnit:测试对象数组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17278233/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
PHPUnit: Test array of objects
提问by 125369
Just jumped into PHPUnit recently, have been reading stuff about it, trying out some examples, in order to get comfortable in writing the tests for my future projects.
最近刚进入 PHPUnit,一直在阅读有关它的内容,尝试一些示例,以便为我未来的项目编写测试。
I need to test this scenario, I have Students Class which is like this:
我需要测试这个场景,我有学生类是这样的:
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;
}
}
And the Student Class
和学生班
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;
}
}
Now how can I test whether the StudentsClass returns an array of objects with the values set and check the values be using the getters from StudentClass
现在我如何测试学生类是否返回一个设置了值的对象数组并检查值是否使用学生类的 getter
Please do throw some light/information/links whichever directs me in the correct path.
请在正确的道路上提供一些指导我的灯光/信息/链接。
Thanks
谢谢
回答by Darren Cook
I've written some example code below; I guessed the parameters to getStudents
were optional filters. We have one test that gets all students. I don't know if they always come back in sorted order, which is why I don't test anything else in the Student class. The second test gets one particular student, and starts to test some of the Student properties.
我在下面写了一些示例代码;我猜参数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());
}
}
This is a good first step. After you use it for a while you'll realize it is quite fragile. I.e. you must have exactly 7 students for the first test to pass. There must be exactly one student called Bob for the second to pass. If your \OldStudents::getStudentByName
is getting data from a database, it will also be slow; we want unit tests to run as quick as possible.
这是很好的第一步。使用一段时间后,您会发现它非常脆弱。也就是说,您必须恰好有 7 名学生才能通过第一次测试。必须有一个叫 Bob 的学生才能让第二个通过。如果您\OldStudents::getStudentByName
从数据库获取数据,它也会很慢;我们希望单元测试尽可能快地运行。
The fix for both of those is to mock the call to \OldStudents::getStudentByName
. Then you can inject your own artificial data, and then you'll only be testing the logic in getAllStudents
. Which in turn means that when your unit test breaks there are only 20 or so lines where you could have broken it, not 1000s.
解决这两个问题的方法是模拟对\OldStudents::getStudentByName
. 然后你可以注入你自己的人工数据,然后你将只测试getAllStudents
. 这反过来意味着当您的单元测试中断时,只有 20 行左右可以中断它,而不是 1000 行。
Exactly how to do the mocking is a whole 'nother question, and could depend on PHP version, and how flexible your code setup is. ("OldStudents" sounds like you are dealing with legacy code and maybe you cannot touch it.)
究竟如何进行模拟是另一个问题,可能取决于 PHP 版本,以及您的代码设置的灵活性。(“OldStudents”听起来像是您正在处理遗留代码,也许您无法触及它。)
回答by Sven
PHPUnit since version 3.1.4 has the assertion "assertContainsOnly" with the parameter "type" which can assert any PHP type (including instances and internal types), and in at least version 3.7 has the assertion "assertContainsOnlyInstancesOf" which explicitly only checks for class instances, not PHP variable types.
PHPUnit 自 3.1.4 版起具有断言“assertContainsOnly”,参数“type”可以断言任何 PHP 类型(包括实例和内部类型),并且至少在 3.7 版中具有断言“assertContainsOnlyInstancesOf”,它明确只检查类实例,而不是 PHP 变量类型。
So the test checking if an array contains only objects of a given type is simply:
因此,检查数组是否仅包含给定类型的对象的测试很简单:
$this->assertContainsOnlyInstancesOf('Student', $students);
Note that this check implicitly tests that $students
is either an array or an object implementing the Traversable interface. Implementing Traversable does not mean you can count, so calling assertCount
afterwards to assert a given number of Student
objects is present is not guaranteed to succeed, but the added check that the return value in fact is an array seems too much bloat to me here. You are creating and returning an array with something in it - it is safe to assume you can count it. But this might not be the case everywhere.
请注意,此检查隐式测试它$students
是一个数组还是一个实现 Traversable 接口的对象。实现 Traversable 并不意味着你可以计数,所以assertCount
之后调用断言给定数量的Student
对象存在并不能保证成功,但是添加的检查返回值实际上是一个数组对我来说似乎太过分了。您正在创建并返回一个包含某些内容的数组 - 可以安全地假设您可以计算它。但这可能不是所有地方的情况。
回答by hakre
You can do that with assertions. First of all you should aquire an actualresult, then do some assertions with it. Compare:
你可以用断言来做到这一点。首先你应该得到一个实际的结果,然后用它做一些断言。相比:
You can assert that it is an array:
你可以断言它是一个数组:
class InternalTypeTest extends PHPUnit_Framework_TestCase
{
public function testFailure()
{
$this->assertInternalType('array', 42);
# Phpunit 7.5+: $this->assertIsArray(42);
}
}
Then you could assert that it is not empty (as you know it must return some data):
然后你可以断言它不是空的(你知道它必须返回一些数据):
class NotEmptyTest extends PHPUnit_Framework_TestCase
{
public function testFailure()
{
$this->assertNotEmpty(ARRAY());
}
}
And then you could assert that each value is of your student-type:
然后你可以断言每个值都是你的学生类型:
class InstanceOfTest extends PHPUnit_Framework_TestCase
{
public function testFailure()
{
$this->assertInstanceOf('Student', new Exception);
}
}
I hope this gives you some pointers. See the link above for a list of common assertions. If you make use of an IDE to wrtie your test it should offer a list of all assertions as well.
我希望这能给你一些提示。有关常见断言的列表,请参阅上面的链接。如果您使用 IDE 来编写测试,它也应该提供所有断言的列表。