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.
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 Students Class returns an array of objects with the values set and check the values be using the getters from Student Class
Please do throw some light/information/links whichever directs me in the correct path.
Thanks
24, $this->assertEquals asserts the array contains the same keys and values, disregarding in what order.
PHPUnit is a unit testing framework for the PHP programming language. It is an instance of the xUnit design for unit testing systems that began with SUnit and became popular with JUnit. Even a small software development project usually takes hours of hard work.
Assertions serve to pass or fail the test if a condition is not met. These assertions will look familiar to you if you've used any other testing framework, like PHPUnit. All assertions contain the same common actions attributes: stepKey , before , and after .
Likewise, PHPUnit mock object is a simulated object that performs the behavior of a part of the application that is required in the unit test. The developers control the mock object by defining the pre-computed results on the actions.
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.
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.
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.
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.)
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With