2

PHP PDO Singleton Class:

<?php

require_once('app/config.php'); // Require constants HOST, DATABASE, USER, PASSWORD

/*

dbConnection class.

Manages connections to and operations on the database. Call dbConnection::getInstance() to return an instance.
Prepare your statements by calling prepareQuery() on the object

Attribute list:

$instance:
> Static self instance to manage database resource

$connection:
> Holds connection resource

$sth:
> Statement handler variable. Handles SQL statements.
_______________________________________________________________________________________________________________

Method list:

getInstance():
> Creates or returns existing connection to the database

prepareQuery():
> Prepares the $sth variable for execution.

bindParameter():
> Binds parameters to the $sth variable.

numRows($query):
> Returns the number of returned from a query

runQuery():
> Executes the current statement on the database

fetchRow():
> Executes the current statement then returns an associative array

fetchObj($className, $parameters = NULL):
> Executes the current statement and returns an object of your specification. Also takes additional parameters to pass to the object's constructor.


*/

class dbConnection
{   
    private static $instance = NULL;
    private $connection;
    private $sth;

    function __construct()
    {
        $this->connection = new PDO('mysql:host=' . HOST . ';dbname=' . DATABASE, USER, PASSWORD);
    }

    function getInstance()
    {
        if (self::$instance == NULL)
            self::$instance = new dbConnection();
        return self::$instance;
    }

    function prepareQuery($query)
    {
        $this->sth = $this->connection->prepare($query);
    }

    function bindParameter($number, $value)
    {
        $this->sth->bindParam($number, $value);
    }

    function numRows()
    {   
        try
        {
            $this->sth->execute();

            $count = $this->sth->rowCount();
            return $count;
        }
        catch(PDOException $e)
        {
            echo __LINE__.$e->getMessage();
        }
    }

    function runQuery()
    {
        try
        {
            $this->sth->execute() or print_r($connection->errorInfo());
        }
        catch(PDOException $e)
        {
            echo __LINE__.$e->getMessage();
        }
    }

    function fetchRow()
    {
        try
        {
            $this->sth->setFetchMode(PDO::FETCH_ASSOC);
            $this->sth->execute();
            return $this->sth;
        }
        catch(PDOException $e)
        {
            echo __LINE__.$e->getMessage();
        }
    }

    function fetchObj($className, $parameters = NULL)
    {
        try
        {
            $this->sth->setFetchMode(PDO::FETCH_CLASS, $className, $parameters);
            $this->sth->execute();
            return $this->sth;
        }
        catch(PDOException $e)
        {
            echo __LINE__.$e->getMessage();
        }
    }
}
?>

How to test singleton? Take an object at a time, which is closed when you are finished with the object at the end.

hakre
  • 193,403
  • 52
  • 435
  • 836
Neru-J
  • 1,623
  • 2
  • 23
  • 38
  • In case this is not about PHPUnit, please clarify what you are trying to test in the first place. Your description above is currently very difficult to make sense of. – Gordon Mar 22 '12 at 18:38

2 Answers2

5

I think you are misapplying the Singleton pattern here.

Nevertheless, testing Singletons is possible. Quoting Testing Code that uses Singletons

PHPUnit has a backup/restore mechanism for static attributes of classes.

This is yet another feature of PHPUnit that makes the testing of code that uses global state (which includes, but is not limited to, global and superglobal variables as well as static attributes of classes) easier.

Also see http://www.phpunit.de/manual/current/en/fixtures.html#fixtures.global-state

The @backupStaticAttributes annotation that is discussed in the section called “@backupStaticAttributes” can be used to control the backup and restore operations for static attributes. Alternatively, you can provide a blacklist of static attributes that are to be excluded from the backup and restore operations like this

So if you wanted to disable the backup, you'd do

class MyPdoTest extends PHPUnit_Framework_TestCase
{
    protected $backupStaticAttributesBlacklist = array(
      'dbConnection' => array('instance')
    );    

    // more test code
}

Also have a look at the chapter on Database Testing

Community
  • 1
  • 1
Gordon
  • 312,688
  • 75
  • 539
  • 559
  • Can you test it without framework "PHPUnit_Framework_TestCase "? – Neru-J Mar 22 '12 at 15:42
  • @Nerujua Can you? Well, I guess so but it doesn't make much sense. PHPUnit is the defacto standard for testing PHP code and when you ask "how to test this code" people will assume you refer to unit-testing with PHPUnit. So if you question is not about PHPUnit, you'd have to clarify what your definition of "testing" is then. – Gordon Mar 22 '12 at 17:05
2

Singletons are bad news, as I have explained here.

More specifically to your question, Singletons are extremely difficult to unit test. Which is one of the reasons why they are bad news.

Use instead.

EDIT TO ADD:

I suppose you could write a set of unit tests where each unit test is in its own test suite and all the test suites are set to run in a separate process. That should isolate each unit test from the others.

The performance would be horrible though, and you're really better off just using a DI approach instead.

(I'm assuming you're using for your unit tests here)

Community
  • 1
  • 1
GordonM
  • 31,179
  • 15
  • 87
  • 129