私はこのクラスのユニットテストを書いています:phpUnit用にEntityManagerをモックする方法は?
<?php
namespace AppBundle\Managers\CRUD;
use Doctrine\ORM\EntityManager;
use CommonLibs\Interfaces\CrudManagerInterface;
use AppBundle\Entity\Pet;
use CommonLibs\Helpers\PaginatorHelper;
use AppBundle\Entity\Person;
use AppBundle\Managers\CRUD\PetManager;
use AppBundle\AppBundle;
class PersonManager extends CrudManagerInterface
{
/**
* @var EntityManager
*/
private $em;
/**
* @var PetManager
*/
private $petManager;
public function __construct(EntityManager $em,PetManager $petManager)
{
$this->em=$em;
$this->petManager=$petManager;
}
/**
* {@inheritDoc}
* @see \CommonLibs\Interfaces\CrudManagerInterface::search()
* @return AppBundle\Entity\Person[]
*/
public function search(array $searchParams, array $order, $page, $limit)
{
$queryBuilder=$this->em->createQueryBuilder();
$queryBuilder=$queryBuilder->select('p')->from('AppBundle:Person','p');
if(isset($searchParams[Person::NAME])) {
$queryBuilder->andWhere('p.name LIKE :name')->setParameter('name','%'.$searchParams[Person::NAME].'%');
}
$petNameSearch=isset($searchParams[Pet::NAME]);
$petTypeSearch=isset($searchParams[Pet::TYPE]);
if($petNameSearch || $petTypeSearch) {
$queryBuilder->join('p.pets','pe');
if($petNameSearch) {
$queryBuilder->andWhere('pe.name LIKE :pet_name')->setParameter('pet_name','%'.$searchParams[Pet::NAME].'$');
}
if($petTypeSearch) {
if(!is_array($searchParams[Pet::TYPE])) {
$searchParams[Pet::TYPE]=array($searchParams[Pet::TYPE]);
}
$queryBuilder->andWhere('pe.type IN (:pet_types)')->setParameter('pet_types',$searchParams[Pet::TYPE]);
}
/**
* @var Doctrine\ORM\Query
*/
$query=$queryBuilder->getQuery();
if((int)$limit>0) {
$query->setFirstResult(PaginatorHelper::calculateFirstResult($page,$limit))->setMaxResults((int)$limit);
}
$results=$query->getResult();
return $results;
}
}
/**
* {@inheritDoc}
* @see \CommonLibs\Interfaces\CrudManagerInterface::getById()
* @return AppBundle\Entity\Person
*/
public function getById($id)
{
return $this->em->getManager('AppBundle:Person')->findById($id);
}
/**
* {@inheritDoc}
* @see \CommonLibs\Interfaces\CrudManagerInterface::add()
*
* @param array $dataToAdd
*
* $dataToAdd Must have one of the follofiwng formats:
*
* FORMAT 1:
* [
* Person:NAME=>"value"
* ]
*
* FORMAT 2:
*
* [
* [
* Person:NAME=>"value"
* ],
* [
* Person:NAME=>"value"
* ],
* [
* Person:NAME=>"value"
* ]
* ]
*
* @return AppBundle\Entiry\Person[] with the modified persons
*/
public function add(array $dataToAdd)
{
/**
* @var AppBundle\Entiry\Person $insertedPersons
*/
$insertedPersons=[];
foreach($dataToAdd as $key=>$data) {
$personToInsert=new Person();
if(is_array($data)) {
$personToInsert=$this->add($data);
if($personToInsert==false) {
return false;
}
} elseif(!$this->setReference($personToInsert,$key,$data)) {
$personToInsert->$$key=$data;
}
if(is_array($personToInsert)) {
$insertedPersons=array_merge($insertedPersons,$personToInsert);
} else {
$this->em->flush($personToInsert);
$insertedPersons[]=$personToInsert;
}
}
if(!empty($insertedPersons)) {
$this->em->flush();
}
return $insertedPersons;
}
/**
* {@inheritDoc}
* @see \CommonLibs\Interfaces\CrudManagerInterface::edit()
*/
public function edit(array $changedData)
{
$em=$this->em->getManager('AppBundle:Person');
foreach($changedData as $id => $fieldsToChange) {
$item=$this->getById($id);
foreach($fieldsToChange as $fieldName=>$fieldValue){
if(!$this->setReference($item,$fieldName,$fieldValue)){
$item->$$fieldName=$fieldValue;
}
}
$em->merge($item);
}
$em->flush();
}
/**
* {@inheritDoc}
* @see \CommonLibs\Interfaces\CrudManagerInterface::delete()
*
* @param array changedData
* Should contain data in the following formats:
* FORMAT 1:
*
* [
* Person::ID=>^an_id^
* Person::NAME=>^a name of a person^
* ]
*
* FORMAT2:
* [
* Person::ID=>[^an_id1^,^an_id2^,^an_id3^...,^an_idn^]
* Person::NAME=>^a name of a person^
* ]
*
* The $changedData MUST contain at least one of Person::ID or Person::NAME.
* Therefore you can ommit one of Person::ID or Person::NAME but NOT both.
*/
public function delete(array $changedData)
{
$queryBuilder=$this->em->createQueryBuilder();
$queryBuilder->delete()->from('AppBundle:Person','p');
$canDelete=false;
if(isset($changedData[Person::ID])) {
if(!is_array($changedData[Person::ID])) {
$changedData[Person::ID]=[$changedData[Person::ID]];
}
$queryBuilder->where('person.id IN (:id)')->bindParam('id',$changedData[Person::ID]);
$canDelete=true;
}
if(isset($changedData[Person::NAME])) {
$queryBuilder->orWhere('person.name is :name')->bindParam('name',$changedData[Person::NAME]);
$canDelete=true;
}
if($canDelete) {
$query=$queryBuilder->getQuery();
$query->execute();
}
return $canDelete;
}
/**
* Set referencing fields to person.
*
* @param AppBundle\Entiry\Person $item The item to set the reference
* @param string $referencingKey A string that Indicates the input field.
* The strings for the param above are defined as constants at AppBundle\Entiry\Person.
* @param mixed $referencingValue The value of referencing key
*
* @return boolean
*/
private function setReference($item,$referencingKey,$referencingValue)
{
/**
* @var AppBundle\Entity\Pet $pet
*/
$pet=null;
if($referencingKey===Person::PET) {
if(is_numeric($referencingValue)) {//Given pet id
$pet=$this->petManager->getById($referencingValue);//Searching pet by id
} elseif (is_object($referencingValue)
&& $referencingValue instanceof AppBundle\Entity\Pet
){//Given directly a pet Object
$pet=$referencingValue;
}
$item->$$referencingKey=$referencingValue;
return true;
}
return false;
}
}
そして私はDoctrineのエンティティマネージャをモックアップしたいと思います。しかし、DoctrineのQuery Builderを正常に使用するためには何を返すべきかわからないのですが、実際のデータベース接続はありません。手伝って頂けますか?
は、だから私のようにエンティティマネージャを模擬していないことを覚えておいてくださいベストプラクティスですが、別のクラスに注入された場合にPersonManager自体をモックします。 –
@DimitriosDesyllasまあ、私はそれが最高のベストプラクティスではないと言いました。単体テストが本当に必要な場合は、模擬/スタブすることができます。それ以外の場合、統合テストを行うことができれば、ユニットテスト(この場合) – DonCallisto