Я хочу использовать Пророчество («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()
на том же классе, и это не проверено.
Какие-либо предложения?
То, чего вы пытаетесь достичь, — это частичное издевательство, которое не поддерживается Пророчеством. Подробнее об этом здесь 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