我想第一次使用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
和Prophecy,据我所知,不允许你:模仿魔术方法(_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()
并且未经过测试。
有什么建议吗?
答案 0 :(得分:1)
你想要实现的是部分模拟,预言不支持。有关详情,请https://github.com/phpspec/prophecy/issues/101和https://github.com/phpspec/prophecy/issues/61。
TL; DR; 设计您的课程时要考虑到单一责任,因此您不必模拟其他功能。
答案 1 :(得分:0)
第一个问题:
不要使用魔法,魔法是邪恶的。 __call可能导致不可预测的行为。
" $ em的承诺和存储库未得到满足" :
不要让你的代码依赖于Class而是Interface。 然后模拟接口而不是类! 您应该模拟ObjectManager而不是EntityManager。 (别忘了改变参数的类型)
最后一点:
在透露之前。
$service->createUserFromLdap()
->shouldBeCalled()
->willReturn(null);
答案 2 :(得分:0)
关于无法模拟不存在的方法的问题,可以使用
http://docs.mockery.io/en/latest/
而不是预言。 Mockery允许你做到这一点。严格来说,这确实打破了一些优秀设计的规则,但另一方面,它有时候非常有用。无论如何,嘲弄是非常相似的,就功能而言,它同样直观且易于使用imo。但是,它们仍然没有发布稳定版本,所以如果您决定使用它,请注意这一点。在这里你可以找到两个库的良好比较
http://everzet.com/post/72910908762/conceptual-difference-between-mockery-and-prophecy