PHPSpec を使い始めようとしていますが、壁にぶつかりました。私が作業するために与えられた既存のコードで適切なものを模倣するために、物事は少し複雑になりましたが、本質的に私の質問は、作成されたばかりのオブジェクトで何かが起こったことをテストすることです.
私は持ってRepositoryFactory
いますcreateRepository(EntityManager $em, $entityName)
Doctrine のEntityManager::getRepository($entityName)
呼び出しだけでRepositoryFactory::getRepository(EntityManager $em, $entityName)
、リポジトリが存在しない場合、THAT 呼び出しRepositoryFactory::createRepository(EntityManager $em, $entityName)
したがって、私のテストでは、リポジトリはからモックされていRepositoryFactory::getRepository
ます。
class MyEntityManagerSpec extends ObjectBehavior
{
function let(..., MyRepositoryFactory $rfact, MyEntityRepository $repo, ...)
{
....
$rfact->getRepository(Argument::any(), Argument::any())
->willReturn($repo);
...
}
function it_sets_a_field_on_repositories(MyEntityRepository $repo)
{
//This class calls its own getRepository, which calls
//getRepository on the factory, which ->willReturn($repo).
//So, effectively (but without mocking the SUT) that means
//$this->getRepository($entityName)->willReturn($repo)
$entityName = 'blah\blah\FakeEntity';
$repo->setField(Argument::any())->shouldBeCalled();
//The above fails with
//"No calls that match MyEntityRepository\P112->setField(*)"
$gotRepo = $this->getRepository($entityName);
$repo->setField(Argument::any())->shouldHaveBeenCalled();
//This fails in the same way
$gotRepo->shouldBe($repo);
//This test passes but doesn't let me verify the property was set
//and is therefore of little help to me
$gotRepo->getField()->shouldNotBeNull();
//I wanted to use shouldBe/shouldHaveBeenCalled but if the field's
//been set that's just as good. Except this fails as well, with
//"is_null(null) not expected to return true, but it did."
}
単独でのテストについて答えが出始める前に、私はそれを認識しています。私は最初にフィールド設定のチェックを書き込もうとしましたMyRepositoryFactory::createRepository
が、同じ種類の問題が発生しました. 内createRepository
でオブジェクトを作成している場合、shouldBe/shouldHaveBeenCalled でテストするモックがありません. しかし、私はここで正しいことをしようとしているので、これが私のテストの間違った場所である場合は、ハッキーなテストに合格するよりも、多くのリファクタリングを行います。
編集:これはテストされている実際のビットです
class MyEntityManager
{
...
public function getRepository($entityName)
{
$repo = parent::getRepository($entityName);
$metaData = $this->getClassMetadata($entityName);
$flag = $this->getTarget() && $metaData->reflClass
->implementsInterface('Caj\Bundle\NameOfBundle\Model\NameOfBundleInterface');
if($flag) {
$repo->setField($this->getField());
}
return $repo;
}
}
上記のビットの $repo は、ここで嘲笑されるべきものです。parent::getRepository
==> RepositoryFactory::getRepository
==>RepositoryFactory::createRepository
さらに、テストがif($flag)
ブロックに入ることはわかっていますが、内部のコードは機能していません。$this->getField()
正常に動作して戻りますが、$repo->setField
それでも null を受け取ります。$repo->setField($field)
ファンキーなロジックのない通常のセッターです。