2015-08-04 3 views
2

Я хочу удалить мой класс обслуживания, который сохраняет 2 объекта. Только тест завершился неудачно, потому что лицо-человек не получает идентификатор от entityManager, потому что оно издевается.Test Doctrine покрасневшее сущность

Есть ли способ обновить объект человека после того, как флеш вызывается в первый раз.

class Foo 
{ 

    ... 

    public function save() 
    { 
     $em = $this->getEntityManager(); 

     $person = new Person(); 
     $person->setName('Dude'); 

     $em->persist($person); 
     $em->flush(); 

     $user = new User(); 
     $user->setPersonId($person->getId()); 
     $user->setEmail('[email protected]'); 

     $em->persist($user); 
     $em->flush(); 
    } 
} 

class FooTest 
{ 

    ... 

    public function testSave_UserIsSaved() 
    { 
     $person = new Person(); 
     $person->setName('dude'); 

     $user = new User(); 
     $user->setPersonId(4); // <-- this is where it gets wrong 
     $user->setEmail('[email protected]'); 


     $person = array(
      'name' => 'Dude', 
     ); 

     $user = array(
      'person_id' => 3, 
      'email'  => '[email protected]', 
     ); 

     $emMock = $this->getMockBuilder('\Doctrine\ORM\EntityManager') 
         ->setMethods(array('persist', 'flush')) 
         ->getMock(); 

     $emMock->expects($this->exactly(2)) 
       ->method('persist') 
       ->with(
        $this->logicalOr(
         $this->equalTo($person), 
         $this->equalTo($user) 
        ) 
       ); 

     $emMock->expects($this->exactly(2)) 
       ->method('flush'); 

     $foo = new Foo($emMock); 
     $foo->save(); 

    } 
} 

ответ

3

Вы можете использовать функцию returnCallback воздействовать на переданный объект (Some example here).

Практически вы можете сказать о методе издевались сохраняться, чтобы сделать некоторые вещи на объект, как, например, рабочие решения, основанные на вашем примере:

class FooTest extends \PHPUnit_Framework_TestCase { 

    public function testSave_UserIsSaved() 
    { 
     $person = new Person(); 
     $person->setName('Dude'); 

     $user = new User(); 
     $user->setPersonId(4); // <-- this is where it gets wrong 
     $user->setEmail('[email protected]'); 

     $emMock = $this->getMockBuilder('\Doctrine\ORM\EntityManager') 
      ->setMethods(array('persist', 'flush')) 
       ->disableOriginalConstructor() 
      ->getMock() 
     ; 

     $emMock->expects($this->exactly(2)) 
      ->method('persist') 
      ->with(
       $this->logicalOr(
        $this->equalTo($person), 
        $this->equalTo($user) 
       ) 
      ) 
      ->will($this->returnCallback(function($o) { 
       if ($o instanceof \Acme\DemoBundle\Model\Person){ 
        $o->setId(4); 
       } 
      })); 



     $emMock->expects($this->exactly(2)) 
      ->method('flush'); 

     $foo = new Foo($emMock); 
     $foo->save(); 

    } 

Испытано с PHPUnit 4.3.5, для некоторых советов проверить this SO Question

Надеюсь, что эта помощь

+0

Спасибо за ваш ответ. Я пробовал что-то подобное раньше, без успеха. Я проверю ваш пример, когда снова буду дома. – WitteStier

+0

Привет, @WitteStier, добро пожаловать! Дайте мне знать, если вам нужна дополнительная помощь. – Matteo

+0

Я был только в состоянии проверить это, когда я не использовал это утверждение, потому что модель человека была обновлена ​​до того, как она была протестирована. $ emMock -> ожидает (this- $> один раз()) метод -> ('сохраняются') -> будет ($ this-> returnCallback (функция ($ о) {если ($ о InstanceOf $ лицо) { $ -> setId (4); }})) – WitteStier

1

Пар точки, главный вопрос первый: если вы тестируете класс Foo тогда все другие сложные зависимости должно быть mocked как это позволяет проверить блок в изоляции, следовательно, «блок» тестирование.

Если вы создаете класс фабрики для создания Person из параметров, и передать это как зависимость к классу Foo в главном приложении, то в вашем наборе тестов вы можете перейти в Мок этого завода, который даст вам Person с предварительно инициализированным идентификатором. Еще лучше, если вы хотите избежать ошибочных результатов теста из-за того, что Person уже будет иметь идентификатор перед тем, как его покраснеть, сделать ложную фабрику возвращением макета Person. Затем вы можете заглушить метод getId макета с помощью обратного вызова, который будет возвращать только нуль, когда был вызван метод флеша EntityManager.

Помимо этого, я рекомендую вам немного изменить свою модель: если Person всегда требуется для User, то требуется его как тип-намекнул параметр конструктору, наряду с любыми другими изначально необходимыми зависимостями. Таким образом, вы можете абстрагировать соотношение между User и Person с association mapping или непосредственно Id, но ваш Foo класса не нужно знать, какие

+0

Спасибо за ваше оповещение. Это просто простой пример моей проблемы. Я издевался над всеми моими зависимостями, кроме моделей. Человек и пользователь - это только пример. Я не хочу добавлять модели на фабрику, потому что есть для многих моделей, и это будет испортить мой конфиг. – WitteStier

Смежные вопросы