单元测试持久层 - Symfony

时间:2016-01-27 07:03:16

标签: php symfony phpunit

我想在Symfony2中测试持久性。我想知道它是否更好的模拟实体并提供给实体经理或者它是更好的模拟实体menager并将实体传递给经理?

我是第一个选项但实体管理器抛出异常而不是对象不是实体主义。如何在PHPUNIT中测试持久性symfony?

1 个答案:

答案 0 :(得分:20)

您应该为持久层编写集成测试,而不是编写单元测试

单元测试中有一条规则“不要嘲笑你不拥有的东西”。

您不拥有Doctrine类和接口,并且您永远无法确定您对所模拟的接口所做的假设是否正确。即使你在编写测试时它们是正确的,你也无法确定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();

        // ...
    }
}

接口将使用doctrine实现:

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();
    }
}

在其他任何地方,您将使用将被存根(或模拟)的接口。在其他任何地方你都不会打到数据库。这使您的测试更快。

您的存根中的实体可以简单地创建或存根。大多数时候我创建实体对象而不是模拟它们。

相关问题