I'm trying to unit test a mapper class with PHPUnit. I can easilly mock the PDO instance that will be injected in the mapper class, but I can't figure out how to mock the PreparedStatement class, as it's generated by the PDO class.
In my case I've extended the PDO class, so I have this:
public function __construct($dsn, $user, $pass, $driverOptions)
{
//...
parent::__construct($dsn, $user, $pass, $driverOptions);
$this->setAttribute(PDO::ATTR_STATEMENT_CLASS,
array('Core_Db_Driver_PDOStatement', array($this)));
}
The point is that Core_Db_Driver_PDOStatement is not injected in the constructor of the PDO Class, it's instanciated statically. And even if I do this:
public function __construct($dsn, $user, $pass, $driverOptions, $stmtClass = 'Core_Db_Driver_PDOStatement')
{
//...
parent::__construct($dsn, $user, $pass, $driverOptions);
$this->setAttribute(PDO::ATTR_STATEMENT_CLASS,
array($stmtClass, array($this)));
}
... it's still a static instanciation as I can't pass my own mocked instance of the prepared statement class.
Any idea ?
Edit: Solution, adapted from the anwser:
/**
* @codeCoverageIgnore
*/
private function getDbStub($result)
{
$STMTstub = $this->getMock('PDOStatement');
$STMTstub->expects($this->any())
->method('fetchAll')
->will($this->returnValue($result));
$PDOstub = $this->getMock('mockPDO');
$PDOstub->expects($this->any())
->method('prepare')
->will($this->returnValue($STMTstub));
return $PDOstub;
}
public function testGetFooById()
{
$arrResult = array( ... );
$PDOstub = $this->getDbStub($arrResult);
}
If you can mock the PDO class just mock out the pdo class and all it's dependencies. There should be no need to care about the statement class or the constructor of the pdo class since you define the input and output via the mocks.
So you need a mock object that returns a mock object.
It might look a little confusing but since you should only test what the class under testing does and nothing else you can pretty much make away with all the other parts of your DB connection.
In this example all you want to figure out is:
If so: All well.
<?php
class myClass {
public function __construct(ThePDOObject $pdo) {
$this->db = $pdo;
}
public function doStuff() {
$x = $this->db->prepare("...");
return $x->fetchAll();
}
}
class myClassTest extends PHPUnit_Framework_TestCase {
public function testDoStuff() {
$fetchAllMock = $this
->getMockBuilder("stdClass" /* or whatever has a fetchAll */)
->setMethods(array("fetchAll"))
->getMock();
$fetchAllMock
->expects($this->once())->method("fetchAll")
->will($this->returnValue("hello!"));
$mock = $this
->getMockBuilder("ThePDOObject")
->disableOriginalConstructor()
->setMethods(array("prepare"))
->getMock();
$mock
->expects($this->once())
->method("prepare")
->with("...")
->will($this->returnValue($fetchAllMock));
$x = new myClass($mock);
$this->assertSame("hello!", $x->doStuff());
}
}
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