Я хочу проверить настойчивость в Symfony2. Интересно, лучше ли это причудливые сущности и предоставить менеджеру сущностей или лучше ли это munk entity menager и передать сущность менеджеру?
Я первый вариант, но диспетчер объектов исключает исключение, чем объект не является дочерней доктриной. Как тестовое сохранение symfony в PHPUNIT?
Вместо написания модульных тестов вы должны написать тесты интеграции для уровня персистентности.
В модульном тестировании есть правило: « Не издевайтесь над тем, что у вас нет ».
Вы не владеете классами Doctrine и интерфейсами, и вы никогда не можете быть уверены, что предположения, которые вы сделали для интерфейсов, которые вы издеваетесь, верны. Даже если они верны в то время, когда вы пишете тест, вы не можете быть уверены, что поведение Доктрины со временем не изменилось.
Всякий раз, когда вы используете сторонний код, вы должны написать интеграционный тест для того, что его использует. Тест интеграции фактически вызовет базу данных и убедитесь, что доктрина работает так, как вы думаете, она работает.
Вот почему хорошо отделяться от сторонних вещей.
В случае доктрины это очень легко. Одна из вещей, которую вы могли бы сделать, это ввести интерфейс для каждого из ваших репозиториев.
interface ArticleRepository { /** * @param int $id * * @return Article * * @throws ArticleNotFoundException */ public function findById($id); }
Вы можете легко высмеять или заглушить такой интерфейс:
class MyServiceTest extends \PHPUnit_Framework_Test_Case { public function test_it_does_something() { $article = new Article(); $repository = $this->prophesize(ArticleRepository::class); $repository->findById(13)->willReturn($article); $myService = new MyService($repository->reveal()); $myService->doSomething(); // ... } }
Интерфейс будет реализован с доктриной:
use Doctrine\ORM\EntityRepository; class DoctrineArticleRepository extends EntityRepository implement ArticleRepository { public function findById($id) { // call doctrine here } }
Реализация – это то, для чего вы собираетесь написать интеграционные тесты. В вашем интеграционном тесте для репозитория вы фактически вызываете базу данных:
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; class ArticleTest extends KernelTestCase { private $em; private $repository; protected function setUp() { self::bootKernel(); $this->em = static::$kernel->getContainer() ->get('doctrine') ->getManager(); $this->repository = $this->em->getRepository(Article::class); } public function test_it_finds_an_article() { $this->createArticle(13); $article = $this->repository->findById(13); $this->assertInstanceOf(Article::class, $article); $this->assertSame(13, $article->getId()); } /** * @expectedException ArticleNotFoundException */ public function test_it_throws_an_exception_if_article_is_not_found() { $this->repository->findById(42); } protected function tearDown() { parent::tearDown(); $this->em->close(); } private function createArticle($id) { $article = new Article($id); $this->em->persist($article); $this->em->flush(); // clear is important, otherwise you might get objects stored by doctrine in memory $this->em->clear(); } }
В другом месте вы будете использовать интерфейс, который будет заострен (или издеваться). В других местах вы не попадете в базу данных. Это делает ваши тесты быстрыми.
Объекты в ваших заглушках могут быть просто созданы или заглушены. Большую часть времени я создаю объекты сущности, а затем издеваюсь над ними.