Skip to content

Recursion

is a method of defining functions in which the function being defined is applied within its own definition

Tagged ,

Mocking PDO and PDOStatement instances for PHP Unit Testing

I think we can all agree that unit testing is important. Seriously, its a given.

I think the real hurdles for adoption of unit testing are installation of a testing framework, and wrapping your mind around the concepts of test composition and mocking/stubbing objects. The mere fact that installation is a pain stops most people out of the gate. Add in the fact that there are so few concrete examples of how test something like the PHP data objects like PDO. No wonder most people think of writing unit tests as a waste of time simply on

I use phpunit to create unit tests. I think this is the defacto standard when it comes to php development. Documentation is plentiful, and most proponents of unit testing have some experience using it. Installation can be done using PEAR. More information can be found on the phpunit site. Seriously, its that simple.

When looking to test a class using a PDO database connector I found this answer on StackOverflow to be extremely helpful, and I want to provide a concrete example.

The example MyClass constructor requires a PDO instance to be passed to it, and a method that returns a result set from a PDOStatement execution. Pretty simple class.

There is also a stub class called “MockPDO” that allows us to circumvent the native PHP PDO constructor, yet still mock the existing methods for further testing. The reason to do this is to get around a constructor error when mocking the PDO class. The unit test shows an example of creating mocks of both the extended PDO class, and a PDOStatement to be injected into the extended PDO class instance.

<?php

/**
 * MyClass
 *
 * Example class to unit test. Constructor requires
 * a valid PDO instance, only method getRecords returns
 * result from example table.
 *
 * @package
 * @version $id$
 * @copyright
 * @license
 */
class MyClass {

    /**
     * _dbh
     *
     * Class PDO instance
     *
     * @var mixed
     * @access public
     */
    public $_dbh;

    /**
     * __construct
     *
     * Constructor method that sets class $_dbh var
     * to the provided PDO instance
     *
     * @param mixed $dbh
     * @access public
     * @return void
     */
    public function __construct($dbh) {
        $this->_dbh = $dbh;
    }

    /**
     * getRecords
     *
     * Returns a result set from query
     *
     * @access public
     * @return void
     */
    public function getRecords() {
        $sql = "SELECT * FROM myclass.records;";
        $sth = $this->_dbh->prepare($sql);
        $sth->execute();
        return $sth->fetchAll();
    }
}

/**
 * MockPDO
 *
 * Mock PDO class to extend PDO, to prevent exceptions from
 * internal PDO calls. Only to be used for Unit Testing.
 *
 * Use this every time you need to test the passing of a PDO instance
 *
 * @uses PDO
 * @package
 * @version $id$
 * @copyright
 * @license
 */
class MockPDO extends PDO {

    /**
     * __construct
     *
     * Empty constructor to prevent errors
     *
     * @access public
     * @return void
     */
    public function __construct() { }
}

/**
 * MyClassTest
 *
 * @uses PHPUnit
 * @uses _Framework_TestCase
 * @package
 * @version $id$
 * @copyright
 * @license
 */
class MyClassTest extends PHPUnit_Framework_TestCase {

    /**
     * testConstructor
     *
     * Test of the MyClass constructor. Only required
     * class variable is a PDO instance
     *
     * @access public
     * @return void
     */
    public function testConstructor() {
        // Create Mocked DB to pass to construtor
        $mockdbh = $this->getMock("MockPDO", array(), array("mysql:dbname=myclass"));

        $myclass = new MyClass($mockdbh);

        // Test to make sure constructor returns a valid MyClass instance
        $this->assertType("MyClass", $myclass);
    }

    /**
     * testGetRecords
     *
     * Test the getRecords method of MyClass
     *
     * @access public
     * @return void
     */
    public function testGetRecords() {
        // Create our mocked classes
        $mockdbh = $this->getMock("MockPDO", array(), array("mysql:dbname=myclass"));
        $mockstatement = $this->getMock("PDOStatement");

        // Variable to store the Return Value of fetchAll
        $records = array(
                            "foo",
                            "bar",
                            "baz",
                        );

        // Expect/Return of mocked statement
        $mockstatement->expects($this->any())
                      ->method("fetchAll")
                      ->will($this->returnValue($records));

        // Expect/Return of mocked PDO
        $mockdbh->expects($this->any())
                ->method("prepare")
                ->will($this->returnValue($mockstatement));

        // Create an instance of our class
        $myclass = new MyClass($mockdbh);

        // Test to make sure getRecords method returns raw queried result set
        $this->assertSame($records, $myclass->getRecords());
    }
}
Tagged , , , , ,

Foursquare API/Geolocation Demo

I created a quick demo to show how you can use the Firefox’s HTML5 geolocation features and a Foursquare API Wrapper to find stuff around your current location. In short: I made a web app that allowed me to find bars, without having to pull out my cell phone. Now you too can inconspicuously look for bars whilst on your laptop.

I used some demo HTML5 code to get the geocoded location in Firefox greater than 3.5. I’ve seen some mixed results and some errors using this, so any feedback on issues found would be appreciated. Of course, you can just manually enter your zipcode if you would like to try this on a non-HTML5 compliant browser, or would like to look up stuff in an area you are not in currently. Pretty simplistic demo, and I’ll add more features/fix bugs in later versions.

I used the PHP wrapper classes Async Foursquare API to interact with the Foursquare API. This sped up time greatly, and I would highly recommend using it as it does offer OAuth functionality as well. Also used the Google Map API to geocode the entered zipcode. The foursquare API requires you pass latitude and longitude to get venues in an area, and this was a quick work around. Of course this demo also uses JQuery, but everyone is (or should be) using it now.

All content is generated from foursquare’s data, and I take no responsibility for the venues that are displayed. What you see is whats on foursquare, and this may be the good interface for finding foursquare venues to close or edit.

I will have links to the code soon, and will add them to this post. Any feedback is appreciated.

Link to the demo

[Updated] – Heres the sources for demo. Update the ‘test.php’  AJAX file with your own Google Maps API key, and download/extract Async wrapper classes into directory to host this locally: 4sq.tar.gz

Tagged , , , ,