【问题标题】:Practices for database testing in Symfony2? How to isolate?Symfony2 中的数据库测试实践?如何隔离?
【发布时间】:2017-05-11 16:02:17
【问题描述】:

目前测试数据库与 Symfony2 交互的最佳实践是什么?我有一个简单的 CRUD 设置,我想确保我的测试正常。现在,我有 4 个测试,每一个都确保创建、更新、删除和列出操作都正常进行。

我的测试用例中有两个魔术方法,__construct 和 __destruct。在它们内部,我使用 'php app/console ...' 调用 exec() 以创建数据库、创建架构并稍后删除数据库。但是,这太慢了,当我有多个测试用例时,它总是会发生。

当涉及到数据库测试和隔离此类测试时,我应该如何进行?

【问题讨论】:

标签: php unit-testing symfony


【解决方案1】:

我认为最好始终从头开始,以确保测试完全隔离。为此,我只是在每次测试之前构建数据库结构,然后用给定测试所需的固定装置填充它。

请注意,我只是在构建所需的数据库表,并且只插入所需的装置。它比加载大型数据库转储快一点。它也更干净,因为测试不共享固定装置(这使它们更易于维护)。

我有一个名为 KernelAwareTest 的基本测试用例类,它可以帮助我构建模式。您可以在 gist 上找到它:https://gist.github.com/1319290

setUp() 启动 Symfony 内核并将对它的引用存储在类属性中(连同对 DIC 和实体管理器的引用)。还调用generateSchema() 来生成数据库模式(它使用Doctrine 中的模式工具)。

默认情况下,它会为实体管理器已知的所有实体生成数据库结构。您可以通过覆盖 getMetadatas() 方法在测试类中更改此行为。

P.S.:我尝试使用内存数据库(sqlite),但并不完美。无论如何,对您在生产中使用的数据库运行测试可能会更好。

【讨论】:

    【解决方案2】:

    数据库测试总是很慢,因为您需要在每次测试之前/之后创建/删除架构。为避免不必要的操作,您可以:

    • 在“setUpBeforeClass”方法中创建架构;
    • 确保您的 4 个测试使用“@depend”注释在一个线程中启动;
    • 在“tearDownAfterClass”方法中删除架构。

    架构只会为您的测试用例创建/删除一次。

    您还可以设置学说以使用 inmemory sqlite 数据库(非常快):

    doctrine:
        dbal:
            driver: pdo_sqlite
            path: :memory:
            memory: true
    

    无论如何,'_construct' 和 '_destruct' 不应该在 phpunit 测试用例中使用,而应该使用 'setUp' 和 'tearDown'。

    【讨论】:

    • 有摆脱我的 exec() 的好方法吗?在我的测试中运行 exec('php app/console dictionary:schema:create') 我觉得很脏。
    【解决方案3】:

    这个问题已经很老了,但今天仍然有效,所以这是我的经验以及我今天在 Symfony 项目中如何处理它。

    我开始使用 SQLite 内存数据库进行测试,并在每个测试用例之前重建 db 模式 + 插入的固定装置。这有两个主要缺点:

    • 还是太慢了:(
    • 在开发和生产中,我使用了 Mysql,但很快就出现了问题,因为 SQLite 根本不具备所需的所有功能,并且有时表现不同

    使用 MSQL 进行测试并在每次测试之前重新构建架构 + 插入固定装置实在是太慢了。所以我一直在寻找替代品...

    我偶然发现了这篇博文:http://alexandre-salome.fr/blog/Symfony2-Isolation-Of-Tests

    这里的人建议在活动数据库事务中运行测试,并在每次测试后简单地回滚任何更改。

    我接受了这个想法并为它创建了一个包:https://github.com/dmaicher/doctrine-test-bundle

    bundle 的设置非常简单,不需要更改任何现有的 php 测试类。在内部,它将教义配置更改为使用自定义数据库连接 + 驱动程序。

    使用这个包,您可以在运行整个测试套件之前简单地创建数据库模式 + 插入固定装置(我更喜欢在自定义 phpunit 引导文件中执行此操作)。使用 phpunit 监听器,所有测试都将在数据库事务中运行。

    我已经使用这个包有一段时间了,对我来说,使用 SQLite、MySQL 或 PostgreSQL 可以完美运行。

    一段时间以来,它也用于 symfony-demo 项目。

    【讨论】:

      【解决方案4】:

      在本地机器上测试很痛苦......所以我开始使用ci系统buddy.works(有免费的独立版本),为此我需要自己解决这个问题。

      结果是:

      • 所有测试都有效
      • 测试正在生产 sql 数据上运行
      • 测试是分开运行的(不是在开发或生产中)——所以我可以 我想要的任何数据库
      • 所有对 git 的推送都经过测试,如果有问题我会收到通知
      • 部署分支的所有推送/拉取请求都会自动上传到生产环境

      这是我的解决方案:

      1. 配置中的第二个参数.yml 以及用于测试的配置
      2. 在生产中我每天都在做 sqldump
      3. 在 ci 上开始测试时,此 sql 备份通过 scp 复制到测试机器
      4. 为了准备这一切,我正在使用 robo.li(我的配置如下)

      /**
      * This is project's console commands configuration for Robo task runner.
      *
      * @see http://robo.li/
      */
      class RoboFile extends \Robo\Tasks
      {
      
      function  loadDb(){
          $this->taskExecStack()
              ->stopOnFail()
              ->exec(" mysql -h mariadb -u root -pqwerty -e 'create database test' ")
              ->exec(" mysql -h mariadb -u root -pqwerty test < test.sql ")
              ->run();
      }
      
      
      function prepareDb(){
          $this->taskExecStack()
              ->stopOnFail()
              ->exec("cp  app/config/parameters-test.yml app/config/parameters.yml")
              ->run();
      
          $this->taskReplaceInFile('app/config/parameters.yml')
              ->from('database_host:     127.0.0.1')
              ->to("database_host:     'mariadb'")
              ->run();
      
          $this->taskReplaceInFile('app/config/parameters.yml')
              ->from('database_user:     dbuser')
              ->to("database_user:     'root'")
              ->run();
      
          $this->taskReplaceInFile('app/config/parameters.yml')
              ->from('database_password: 123')
              ->to("database_password: 'qwerty'")
              ->run();
      
      
      }
      

      }

      我希望它可以帮助您创建如何组织所有这些的想法。使用独立的 ci 很难设置,但它确实是个好主意

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-12-17
        • 1970-01-01
        • 1970-01-01
        • 2011-09-12
        • 1970-01-01
        • 2021-04-04
        • 2016-02-08
        • 2012-12-23
        相关资源
        最近更新 更多