Как издеваться над методом из класса, который вы тестируете, с Пророчеством?

Я хочу использовать Prophecy ("phpspec / prophecy-phpunit") впервые для создания модульных тестов для моих классов. Я хочу протестировать функцию, которая вызывает другую функцию в том же сервисе, вот код:

class UserManager
{
    private $em;
    private $passwordHelper;

    public function __construct(\Doctrine\ORM\EntityManager $em, \MainBundle\Helper\PasswordHelper $passwordHelper)
     {
         $this->em = $em;
         $this->passwordHelper = $passwordHelper;
     }

     public function getUserForLdapLogin($ldapUser)
     {
          $dbUser = $this
              ->em
              ->getRepository('MainBundle:User')
              ->findOneBy(array('username' => $ldapUser->getUsername()));

         return (!$dbUser) ?
              $this->createUserFromLdap($ldapUser) :
              $this->updateUserFromLdap($ldapUser, $dbUser);
     }

Первая проблема у меня была в том, что я использовал findOneByUsername и пророчество, насколько мне известно, не позволяет вам: высмеивать магические методы (_call за EntityRepository), издевайтесь над несуществующими методами, насмехайтесь над классом, который вы тестируете. Если это правда, я в некотором роде, что означает, что я не могу протестировать эту функцию без тестирования других функций в классе.

Пока что мой тест выглядит так:

class UserManagerTest extends \Prophecy\PhpUnit\ProphecyTestCase
{

      public function testGetUserForLdapLoginWithNoUser()
      {
          $ldapUser = new LdapUser();
          $ldapUser->setUsername('username');

          $em = $this->prophesize('Doctrine\ORM\EntityManager');
          $passwordHelper = $this->prophesize('MainBundle\Helper\PasswordHelper');

          $repository = $this->prophesize('Doctrine\ORM\EntityRepository');
          $em->getRepository('MainBundle:User')->willReturn($repository);
          $repository->findOneBy(array('username' => 'username'))->willReturn(null);

          $em->getRepository('MainBundle:User')->shouldBeCalled();
          $repository->findOneBy(array('username' => 'username'))->shouldBeCalled();

          $service = $this->prophesize('MainBundle\Helper\UserManager')
            ->willBeConstructedWith(array($em->reveal(), $passwordHelper->reveal()));

          $service->reveal();
          $service->getUserForLdapLogin($ldapUser);
     }
}

И, конечно же, испытания не пройдены, потому что $emи хранилище не выполняются. Если я создаю экземпляр класса, который тестирую, тесты не пройдены, потому что функция вызывает createUserFromLdap() на том же классе, и это не проверено.

Какие-либо предложения?

3 ответа

То, чего вы пытаетесь достичь, - это частичное издевательство, которое не поддерживается Пророчеством. Подробнее об этом здесь https://github.com/phpspec/prophecy/issues/101 и https://github.com/phpspec/prophecy/issues/61.

TL; DR; Проектируйте свои классы с единственной ответственностью, чтобы вам не приходилось издеваться над другими функциями.

Первая проблема:

Не используйте магию, магия это зло. __call может привести к непредсказуемому поведению.

"Обещания на $em, а хранилище не выполнены":

Не делайте свой код зависимым от класса, а от интерфейса. Тогда издевайтесь над интерфейсом вместо класса! Вы должны издеваться над ObjectManager вместо EntityManager. (не забудьте изменить тип ваших параметров)

И последний пункт:

Прежде чем раскрыть.

$service->createUserFromLdap()
   ->shouldBeCalled()
   ->willReturn(null);

Что касается вашей проблемы невозможности высмеивать методы, которые не существуют, вы можете использовать

http://docs.mockery.io/en/latest/

вместо пророчества. Издевательство позволяет вам сделать именно это. Строго говоря, это нарушает некоторые правила хорошего дизайна, но, с другой стороны, иногда это просто очень полезно. В любом случае, насмешки очень похожи, что касается функций, и они одинаково интуитивно понятны и просты в использовании. Тем не менее, они все еще не выпустили стабильную версию, так что просто знайте об этом, если вы решите использовать ее.

Здесь вы можете найти хорошее сравнение двух библиотек

http://everzet.com/post/72910908762/conceptual-difference-between-mockery-and-prophecy

Другие вопросы по тегам