Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

phpunit: mock object not fooling php

I'm going through the zend tutorials and I am testing a class with a mock object with phpunit. When I pass a mock created from Zend\Db\TableGateway to my class, who's constructor expects a Zend\Db\TableGateway, I get an type error:

"...Argument 1 passed to Album\Model\AlbumTable::__construct() must be an instance of Zend\Db\TableGateway\TableGateway, instance of Mock_TableGateway_65b55cb0 given..."

Is this supposed happen? Are phpunit mock objects supposed to be able to "fool" the class?

Here is the real class:

class AlbumTable {
    protected $tableGateway;

    public function __construct(TableGateway $tableGateway) {
        $this->tableGateway = $tableGateway;
    }

    public function fetchAll() {
        $resultSet = $this->tableGateway->select();
        return $resultSet;
    }

    public function getAlbum($id){
        $id = (int) $id;
        $rowset = $this->tableGateway->select(array('id' => $id));
        $row = $rowset->current();
        if(!$row) {
            throw new \Exception("Couldn't find row: $id");
        }
        return $row;
    }

    public function saveAlbum(Album $album) {
        $data = array(
            'artist' => $album->artist,
            'title' => $album->title,
        );

        $id = (int)$album->id;
        if ($id == 0) {
            $this->tableGateway->insert($data);
        } else {
            if ($this->getAlbum($id)) {
                $this->tableGateway->update($data, array('id' => $id));
            } else {
                throw new \Exception('Form id does not exist');
            }
        }
    }

    public function deleteAlbum($id) {
        $this->tableGateway->delete(array('id' => $id));
    }

}

and the test:

class AlbumTableTest extends PHPUnit_Framework_TestCase {
    public function testFetchAllReturnsAllAlbums() {
        $resultSet = new ResultSet();
        $mockTableGateway = $this->getMock('Zend\Db\TableGateway',
            array('select'), array(), '', false);

        $mockTableGateway->expects($this->once())
            ->method('select')
            ->with()
            ->will($this->returnValue($resultSet));

        $albumTable = new AlbumTable($mockTableGateway);
        $this->assertSame($resultSet, $albumTable->fechAll());
    }
}

and the error:

Time: 102 ms, Memory: 5.00Mb

There was 1 error:

1) AlbumTest\Model\AlbumTableTest::testFetchAllReturnsAllAlbums
Argument 1 passed to Album\Model\AlbumTable::__construct() must be an instance of Zend\Db\TableGateway\TableGateway, instance of Mock_TableGateway_65b55cb0 given, called in C:\Users\MEEE\Google Drive\code\iis\www\CommunicationApp\module\Album\test\AlbumTest\Model\AlbumTableTest.php on line 20 and defined

C:\Users\MEEE\Google Drive\code\iis\www\CommunicationApp\module\Album\src\Album\Model\AlbumTable.php:9
C:\Users\MEEE\Google Drive\code\iis\www\CommunicationApp\module\Album\test\AlbumTest\Model\AlbumTableTest.php:20

FAILURES!
Tests: 4, Assertions: 9, Errors: 1.
like image 407
red888 Avatar asked Feb 25 '14 14:02

red888


1 Answers

You are not mocking the correct class. You are creating a mock of a Zend\Db\TableGateway and you need to actually mock Zend\Db\TableGateway\TableGateway

Change you test code to:

    $mockTableGateway = $this->getMock('Zend\Db\TableGateway\TableGateway',
        array('select'), array(), '', false);

Your mock was failing a type-hint because your not mocking the correct class.

Mock objects will extend the class that you are mocking, so they will be an instance of the class being mocked.

like image 152
Schleis Avatar answered Oct 14 '22 10:10

Schleis