2014-01-23 34 views
2

我正在尝试为使用Propel查询的类编写单元测试(使用phpunitmockery)。
如何模拟查询$contact = ClientContactQuery::create()->findPK($id);嘲笑函数中的Propel查询(Symfony2)

我很努力地找到任何这方面的例子。

我的班级;

<?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; 
    } 

} 

到目前为止我的测试用例;

<?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); 
    } 

} 

回答

4

静态函数对单元测试不太好,请不要创建私有方法并模拟它。

我强烈建议创建一个查询工厂。这不仅会让你有能力注入并单元测试你的代码,但是如果你想在将来使用XYZ orm代替Propel,它将使生活更轻松。

<?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); 
    } 

} 
1

你真的不能嘲笑它,因为你对它有“硬”依赖性。所以,要解决这个问题,你应该考虑从getContact方法的查询中移动“硬”依赖。

你可以做到这一点的方法有三种:

  1. 创建您的私有方法,E。 G。 “getQueryFindByPk”,然后在你的Contacts类中模拟它,以返回你所需要的。
  2. 将查询实例传递给构造函数,但据我所知,可以有多个查询实例。
  3. 创建类似于QueryFactory,Repository或QueryBuilder,它可以返回给你的查询实例。

所以,再一次,问题是对查询具有“硬”依赖性。