Я пытаюсь начать с PHPSpec, и я ударил стену. Вещи стали немного запутанными, чтобы высмеивать правильные вещи в уже существующем коде, с которым мне было поручено работать, но по сути мой вопрос включает в себя тестирование того, что что-то случилось с объектом, который только что был создан.
у меня есть RepositoryFactory
который имеет createRepository(EntityManager $em, $entityName)
доктрина-х EntityManager::getRepository($entityName)
просто звонки RepositoryFactory::getRepository(EntityManager $em, $entityName)
и если хранилище не существует, это вызывает 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
все еще получает ноль. $repo->setField($field)
нормальный сеттер без лишней логики.
Задача ещё не решена.
Других решений пока нет …