Как создать тесты с объектами Doctrine, не сохраняя их (как установить id)
Я работаю над тестами для проекта Symfony2, и сейчас я ищу способ создания тестов с объектами сущностей, не сохраняя их. Проблема в том, что id является частным полем, и для этого нет настройки. Я могу создать новый объект и установить некоторые свойства, но я не могу проверить что-либо с вызовами getId().
$entity = new TheEntity();
// Can't set ID!
$entity->setProperty('propertyValue');
$name = $entity->getProperty(); // OK
$id = $entity->getId(); // not OK - null
Резолюции, о которых я знаю:
- Инициализация всего ядра (Symfony WebTestCase:: createKernel()) и сохранение сущностей
- Создание макета для каждой сущности, которая вернет действительный идентификатор
- Взломается как статический метод в классе TheEntity, возвращающем инициализированный объект, или добавление setter для поля id
Каков рекомендуемый способ справиться с этим, как получить объект для тестирования чистым и быстрым способом с идентификатором набора?
Edit
Оказалось, что я могу решить это с насмешкой... извините, я все еще учусь. Я искал чистый, стандартный, но быстрый способ добиться успеха. Однако я забыл о втором параметре getMock()
- то есть мне не нужно издеваться над каждым методом сущности, которую я собираюсь использовать. Я хотел избежать нескольких ->expects()->method()->will()
и т.д. И это достигается добавлением: array('getId')
. Этот вспомогательный метод решает проблему:
protected function getEntityMock($entityClass, $id)
{
$entityMock = $this->getMock($entityClass, array('getId'));
$entityMock
->expects($this->any())
->method('getId')
->will($this->returnValue($id));
return $entityMock;
}
При создании многих объектов одного и того же класса все можно, конечно, упростить, используя дополнительные вспомогательные методы, такие как:
protected function getTheEntityMock($id)
{
return $this->getEntityMock('\The\NameSpace\TheEntity', $id);
}
Единственное ограничение заключается в том, что сам объект не может использовать свойство id
, только getId()
getter.
Любые ценные данные по-прежнему приветствуются, но я верю, что PHPUnit getMock()
решил это хорошо.
Ответы
Ответ 1
Вы можете настроить doctrine для использования базы данных в памяти в app/config/config_test.yml
.
# app/config/config_test
doctrine:
dbal:
driver: pdo_sqlite
path: :memory:
memory: true
Это ускоряет процесс, и вы можете быстро сохранить некоторые приборы в методе setUp()
, который будет иметь (автоматически сгенерированный) идентификатор после промывки... все, не испортив вашу "настоящую" базу данных.
Вы можете найти вдохновение в этом ответе и этот пост в блоге.
Ответ 2
Другим способом является создание дочернего объекта вашей сущности (это может жить в папке с тестами, если вы хотите сохранить чистоту), а затем добавить метод setId() к дочернему
class TestableEntity extends \My\Namespace\Entity
{
public function setId($id)
{
$this->id = $id;
return $this;
}
}
Затем ваши тесты должны проверить TestableEntity, а не реальную сущность.
Пока свойство id в \My\Namespace\Entity защищено, а не частное, оно может быть установлено через TestableEntity.
Ответ 3
Это немного устарело, но стоит сказать, что лучше всего иметь вспомогательный метод, который использует Reflection для изменения эти защищенные значения.
Пример:
public function set($entity, $value, $propertyName = 'id')
{
$class = new ReflectionClass($entity);
$property = $class->getProperty($propertyName);
$property->setAccessible(true);
$property->setValue($entity, $value);
}
поместите это в базовый тестовый класс, который вы расширяете или используете в trait
, и просто используйте его, когда вам нужно что-то подобное в тесте. Таким образом, вы сможете писать тесты, не создавая грязных изменений.