문제

I am trying to write a unit test (using phpunit and mockery) for a class that uses a Propel query.
How do I mock the query $contact = ClientContactQuery::create()->findPK($id);

I am struggling to find any examples for this.

My class;

<?php
namespace MyBundle\Classes;

use MyBundle\Model\ClientContactQuery;
use MyBundle\Model\ClientContact;

class Contacts {

    protected $_cache;

    public function __construct($cache)
    {
        $this->_cache = $cache;
    }

    public function getContact($id)
    {
        $contact = ClientContactQuery::create()->findPK($id);

        if (! $contact) {
            throw new NotFoundHttpException('Client contact not found.');
        }

        return $contact;
    }

}

My test case so far;

<?php
namespace MyBundle\Tests\Classes;

use Mockery as m;
use MyBundle\Classes\Contacts as c;

class ContactsTest extends \PHPUnit_Framework_TestCase
{
    public function tearDown()
    {
        m::close();
    }

    public function testGetValidContact()
    {
        // Arrange
        $cache = m::mock('cache');

        // Act
        $contact = new c($cache);
        // am lost at this point :-(

        // Assert
        $this->assertInstanceOf('MyBundle\Classes\Contacts', $contact);
    }

}
도움이 되었습니까?

해결책

Static functions do not play nice with unit testing, and please do not create a private method and mock it.

I'd highly suggest creating a Query Factory. Not only this will give you ability to inject and unit test your code, but it will make life easier if you want to use XYZ orm instead Propel in the future.

#

<?php
namespace MyBundle\Classes;

use MyBundle\Model\ClientContactQuery;
use MyBundle\Model\ClientContact;

class Contacts {

    protected $_cache;

    /** @var QueryFactory */
    private $queryFactory;


    public function __construct( $cache, QueryFactory $queryFactory ) {
        $this->_cache = $cache;
        $this->queryFactory = $queryFactory;
    }

    public function getContact( $id ) {
        $contact = $this->queryFactory->newClientContactQuery()->findPK($id);

        if (! $contact) {
            throw new NotFoundHttpException('Client contact not found.');
        }

        return $contact;
    }

}

#

<?php
class QueryFactory {

    const CLASS_NAME = __CLASS__;

    public function newClientContactQuery() {
        return ClientContactQuery::create();
    }

    public function newSomeOtherQuery() {
        return SomeOtherQuery::create();
    }

}

#

<?php
namespace MyBundle\Tests\Classes;

use Mockery as m;
use MyBundle\Classes\Contacts as c;

class ContactsTest extends \PHPUnit_Framework_TestCase {
    public function tearDown() {
        m::close();
    }

    public function testGetValidContact() {
        $cache              = m::mock( 'cache' );
        $queryFactory       = m::mock( QueryFactory::CLASS_NAME );
        $clientContactQuery = m::mock( 'ClientContanctQuery' );

        $contact = new c($cache, $queryFactory);

        $queryFactory->shouldReceive('newClientContactQuery')->with()->once()->andReturn( $clientContactQuery );
        $clientContactQuery->shouldReceive('findPK')->with('myTestInputId')->once->andReturn('something?');

        $this->assertInstanceOf('MyBundle\Classes\Contacts', $contact);
    }

}

다른 팁

You really can`t mock it, because you have "hard" dependency on it. So, to solve this problem, you should consider to move "hard" dependency on query from getContact method.

You can do it in three ways:

  1. Create your private method, e. g. "getQueryFindByPk", and then mock it, on your Contacts class, to return what you need.
  2. Pass query instance to constructor, but as I understand, you can have multiple query instances.
  3. Create something like QueryFactory, Repository or QueryBuilder, which can return to you instance of query.

So, once again, problem is in having "hard" dependency on query.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top