单元测试持久层-Symfony [英] Unit test persistence layer - Symfony

查看:117
本文介绍了单元测试持久层-Symfony的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想测试Symfony2中的持久性.我想知道这是否是更好的模拟实体并提供给实体管理器,还是更好的模拟实体管理者并将实体传递给管理器?

I want to test persistence in Symfony2. I wonder whether it is better mock entities and provide to entity manager or whether it is better mock entity menager and pass entity to manager ?

我是第一选择,但是实体管理器抛出的异常比对象不是实体学说.如何在PHPUNIT中测试持久性symfony?

I first option but entity manager throw exception than object is not entity doctrine. How test persistence symfony in PHPUNIT?

推荐答案

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

Rather than writing unit tests you should write integration tests for the persistence layer.

单元测试中有一条规则"不要嘲笑您不拥有的东西".

There's a rule in unit testing "Don't mock what you don't own".

您既不拥有Doctrine类,也不拥有接口,并且您永远无法确保对模拟的接口所做的假设是正确的.即使在编写测试时它们是正确的,也不能确定Doctrine的行为不会随时间变化.

You don't own Doctrine classes nor interfaces, and you can never be sure that assumptions you made to the interfaces you mocked are true. Even if they're true at the time you write the test, you cannot be sure that Doctrine's behaviour didn't change over time.

无论何时使用第三方代码,都应为使用该代码编写一个集成测试.集成测试实际上将调用数据库,并确保该理论以您认为的方式工作.

Whenever you use 3rd party code you should write an integration test for whatever uses it. Integration test will actually call the database and make sure that doctrine works the way you think it works.

这就是为什么与第三方的东西脱钩的好处.

在学说的情况下,这非常容易.您可以做的一件事就是为每个存储库引入一个界面.

In case of doctrine it's very easy. One of the things you could do is to introduce an interface for each of your repositories.

interface ArticleRepository
{
    /**
     * @param int $id
     *
     * @return Article
     *
     * @throws ArticleNotFoundException
     */
    public function findById($id);
}

您可以轻松地模拟或存根这样的界面:

You can easily mock or stub such an interface:

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

        // ...
    }
}

该界面将以以下原则实现:

The interface will be implemented with doctrine:

use Doctrine\ORM\EntityRepository;

class DoctrineArticleRepository extends EntityRepository implement ArticleRepository
{
    public function findById($id)
    {
        // call doctrine here
    }
}

该实现是您要编写集成测试的目的.在对存储库的集成测试中,您实际上将调用数据库:

The implementation is what you're gonna write integration tests for. In your integration test for the repository you'll actually call the database:

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

在其他任何地方,您都将使用将被打桩(或嘲笑)的接口.您不会在其他任何地方访问数据库.这样可以使您的测试速度更快.

Everywhere else, you'll use the interface which will be stubbed (or mocked). Everywhere else you won't hit the database. This makes your tests fast.

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

Entities in your stubs can be simply created or stubbed. Most of the time I create entity objects rather then mock them.

这篇关于单元测试持久层-Symfony的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆