2016-01-27 4 views
3

Я хочу проверить настойчивость в Symfony2. Интересно, лучше ли это причудливые сущности и предоставить менеджеру сущностей или лучше ли это munk entity menager и передать сущность менеджеру?Единица измерения уровня тестирования - Symfony

I первый вариант, но сущность-менеджер исключает исключение, чем объект не является доктриной сущности. Как тестовое сохранение symfony в PHPUNIT?

ответ

20

Вместо того, чтобы писать модульных тестов вы должны написать интеграционные тесты для слоя сохранения.

Существует правило в модульном тестировании «Не издевайтесь над тем, что вы не являетесь».

У вас нет классов и интерфейсов 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(); 
    } 
} 

Везде еще, вы будете использовать интерфейс, который будет погасил (или высмеивал). В других местах вы не попадете в базу данных. Это делает ваши тесты быстрыми.

Объекты в ваших заглушках могут быть просто созданы или прорезаны. Большую часть времени я создаю объекты сущности, а затем издеваюсь над ними.

+4

Я бы даже пошел еще на 1 шаг и сделаю свой ArticleRepository оболочкой слоя Doctrine вместо расширения EntityRepository. В противном случае создание этого класса по-прежнему не в вашем распоряжении, а классы, которым они нужны, по-прежнему зависят от EntityManager для доступа к нему. –

+1

Обертка действительно является вариантом. Во многих случаях лучше, так как вы можете вводить других соавторов в ваш репозиторий, а также менеджер сущностей! –

+0

Вы бы использовали драйвер SQLite в памяти или тот же драйвер, который использовался в производстве? – noisebleed

Смежные вопросы