Home » Php » How will one make an unit test in PHP if an ORM layer is used?

How will one make an unit test in PHP if an ORM layer is used?

Posted by: admin July 12, 2020 Leave a comment

Questions:

I have a class let’s say Person. The ORM layer has generated based on the sql structure the corresponding objects. The class person has a method: Get($id). In the Get method, the object Person is called and the field from the table are retrieved.

I basically want to make the following unit test: create a new person and check if the Get method is returning the right information.

  • How is the unit testing supposed to work in this condition ?
  • Do I need to create a separate database ( just the structure ), and make the creation/selection from that database?
  • Should the boostrap file load the same configuration as the framework I’m using but change the configuration file so It works with the fake database ?
  • Should I clean the new database each after each test ?

    I was also wandering after seeing your responses if simulating an ORM response without actually building a new database is not the way to go ?

  • How to&Answers:

    How is the unit testing supposed to work in this condition ?

    Generally, you should split your unittests mentally in two parts:

    • one part of your code is testable without the database, so you can stub or mock the methods that do the database access
    • the other part of your tests needs to work with the database, since it tests if the ORM is used correctly.

    Do I need to create a separate database

    This depends on your needs. Rails apps generally have testing/development/production “environments” – database, configuration, storage directories.
    Testing is for running unit tests, dev for developing things and production for running the live server. While developing, you run against the dev configuration and thus your development database. For unit tests, the testing env is used which has the benefit that i.e. users in the database are not deleted or broken.

    I like that concept; in my phpunit tests I often do have a switch in the bootstrap that changes which configuration file is loaded. Just remember that your development database often contains more data than a single unit test needs, and you probably hand-crafted that data and do not want to lose. Also, another database does not cost money.

    Should I clean the new database each after each test?

    I mostly clean the tables only that will be used in the test. Cleaning your database makes sure you don’t get side-effects from previous tests.

    Answer:

    Check out Phactory. I prefer it over the database extensions included in PHPUnit and it makes it really easy to insert records into your test db.

    require_once 'Phactory/lib/Phactory.php';
    
    Phactory::setConnection(new PDO('sqlite:test.db'));
    
    Phactory::define('user', array('name'  => 'Test User',
                                   'email' => '[email protected]'));
    
    $user = Phactory::create('user'); // creates a row in the 'users' table
    
    print("Hello, {$user->name}!"); // prints "Hello, Test User!"
    

    Your System Under Test (SUT) will need to connect to your test database. The idea is that you populate just the records you need for the method you are testing. The orm layer shouldn’t matter if the test db has all the same tables and fields as your production database.

    Answer:

    PHPUnit also provides some help with this, have a look at Database Testing.

    Essentially you can write you Test classes so that they extend PHPUnit_Extensions_Database_TestCase and then use the getConnection() and getDataSet() functions to load up data for the test.

    require_once 'PHPUnit/Extensions/Database/TestCase.php';
    
    class PersonTest extends PHPUnit_Extensions_Database_TestCase
    {
        protected function getConnection() {
            $pdo = new PDO('mysql:host=localhost;dbname=application_test', 'root', '');
            return $this->createDefaultDBConnection($pdo, 'application_test');
        }
    
        protected function getDataSet() {
            return $this->createMySQLXMLDataSet('person.xml');
        }
    

    Then you can define exactly what you want to test in the database in the XML.

    You can also assert that the resulting DataSet from your tests is equal to what you expect with:

    public function testCreate() {
        // Execute some code with your ORM to create a person.
    
        $actual = new PHPUnit_Extensions_Database_DataSet_QueryDataSet($this->getConnection());
        $actual->addTable('person');
        $expected = $this->createMySQLXMLDataSet('person_create_expected.xml');
        $this->assertDataSetsEqual($expected, $actual);
    }
    

    In this example, we are only comparing the resulting person table… So person_create_expected.xml should only contain the person table as well.

    To create the XML’s you can use mysqldump.

    mysqldump --xml -t -u root -p application_test > person.xml