我应该单元测试扩展Sonata BaseEntityManager类的测试类吗?

时间:2018-02-04 14:20:56

标签: unit-testing symfony sonata

以下是扩展BaseEntityManager的代码的一部分:

namespace Vop\PolicyBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Persistence\ObjectRepository;
use Sonata\CoreBundle\Model\BaseEntityManager;

class AdditionalInsuredTypeManager extends BaseEntityManager
{
    /**
     * @param int $productId
     *
     * @return ArrayCollection
     */
    public function getProductInsuredTypes($productId = null)
    {
        $repository = $this->getRepository();

        $allActiveTypes = $repository->findAllActive();

        // other code
    }

    /**
     * @return AdditionalInsuredTypeRepository|ObjectRepository
     */
    protected function getRepository()
    {
        return parent::getRepository();
    }
}

在这里,我正在尝试编写单元测试:

public function testGetProductInsuredTypes()
    {
        $managerRegistry = $this->getMockBuilder(\Doctrine\Common\Persistence\ManagerRegistry::class)
            ->getMock();

        $additionalInsuredTypeManager = new AdditionalInsuredTypeManager(
            AdditionalInsuredTypeManager::class,
            $managerRegistry
        );

        $additionalInsuredTypeManager->getProductInsuredTypes(null);
    }

有什么问题:

  • 我在嘲笑ManagerRegistry,但我知道我不应该嘲笑我不拥有的东西。但这是构造函数的必需参数。
  • 我收到错误:

无法找到类Vop \ PolicyBundle \ Entity \ AdditionalInsuredTypeManager的映射信息。请检查' auto_mapping'选项(http://symfony.com/doc/current/reference/configuration/doctrine.html#configuration-overview)或将捆绑包添加到'映射'学说配置中的部分。  /home/darius/PhpstormProjects/vop/vendor/sonata-project/core-bundle/Model/BaseManager.php:54  /home/darius/PhpstormProjects/vop/vendor/sonata-project/core-bundle/Model/BaseManager.php:153  /home/darius/PhpstormProjects/vop/src/Vop/PolicyBundle/Entity/AdditionalInsuredTypeManager.php:46  /home/darius/PhpstormProjects/vop/src/Vop/PolicyBundle/Entity/AdditionalInsuredTypeManager.php:21  /home/darius/PhpstormProjects/vop/src/Vop/PolicyBundle/Tests/Unit/Entity/AdditionalInsuredTypeManagerTest.php:22

我不知道如何修复此错误,但这实际上需要对扩展我认为的BaseEntityManager做一些事情。

我看到错误是由这一行引起的:

$repository = $this->getRepository();

我甚至无法从构造函数中注入存储库,因为父构造函数没有这样的参数。

关于测试的信息非常少:

https://sonata-project.org/bundles/core/master/doc/reference/testing.html

1 个答案:

答案 0 :(得分:0)

我不能告诉你测试你的存储库是否有用,除了你很可能不会扩展doctrine的实体经理之外,我也不能指出你的错误。如果有任何东西使用自定义EntityRepository或编写一个注入EntityManager的服务(或更好的EntityRegistry):

class MyEntityManager
{
    private $entityManager;

    public function __construct(EntityManager $entityManager)
    {
        $this->entityManager = $entityManager;
    }

    public function getProductInsuredTypes($productId = null)
    {
        $repository = $this->entityManager->getRepository(Product::class);

        $allActiveTypes = $repository->findAllActive();

        // other code
    }
}

我能给你的是解释我如何处理测试存储库:

我认为单元测试,尤其是模拟测试,看起来有点浪费。它们只会将您绑定到当前的实现,并且由于任何相关性被嘲笑,您很可能不会测试任何行为。

可能有用的是进行功能测试,其中提供真实的数据库连接,然后对存储库执行查询以查看它是否确实返回了预期的结果。我通常这样做是为了更复杂的查询或使用高级教义功能,如使用自定义ResultsetMap的本机查询。在这种情况下,您不会模拟EntityManager,而是使用Doctrine的TestHelper来创建内存中的sqlite数据库。这看起来像这样:

protected $entityManager;

protected function setUp()
{
    parent::setUp();

    $config = DoctrineTestHelper::createTestConfiguration();
    $config->setNamingStrategy(new UnderscoreNamingStrategy());
    $config->setRepositoryFactory(new RepositoryFactory());

    $this->entityManager = DoctrineTestHelper::createTestEntityManager($config);
}

缺点是,您将手动注册自定义类型和侦听器,这意味着行为可能与您的生产配置不同。此外,您仍然需要设置架构并为测试提供夹具。您也很可能不会在生产中使用SQLite,因此这是另一个偏差。好处是您不必在运行之间处理清理数据库,并且可以轻松地并行运行测试,而且通常比设置完整的测试数据库更快更容易。

最终选项与前一个选项有些接近。您可以拥有一个测试数据库,您可以在参数,环境变量或config_test.yml中定义,然后可以引导内核并从DI容器中获取实体管理器。 Symfony的WebTestCase可以作为这种方法的参考。

缺点是,您必须启动内核并确保具有用于开发,生产和测试的单独数据库设置,以确保您的测试数据不会弄乱任何内容。您还必须设置您的架构和灯具,此外,您可以轻松地遇到测试未被隔离并开始变得棘手的问题,例如:以不同顺序运行或仅运行部分测试套件时。显然,由于这是通过引导应用程序进行的完全集成测试,因此与单元测试或较小功能测试相比,性能足迹明显更高,而应用程序缓存可能会给您带来额外的麻烦。

根据经验:

  • 在执行最基本的查询时我信任Doctrine,因此不会为简单的查找方法测试存储库。
  • 当我编写关键查询时,我更喜欢在更高层上间接测试它们,例如在验收测试中确保页面显示信息。
  • 当我遇到存储库问题或需要在较低层进行测试时,我先从功能测试开始,然后继续进行存储库的集成测试。

TL;博士

  • 存储库的单元测试大多没有意义(在我看来)
  • 如果需要,功能测试可以通过合理的努力单独测试简单查询。
  • 集成测试可确保最具生产力的行为,但设置和维护更加痛苦