繁体   English   中英

Symfony2中的数据库测试实践? 怎么隔离?

[英]Practices for database testing in Symfony2? How to isolate?

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

在我的测试用例中,我有两个神奇的方法,__ construct和__destruct。 在它们内部,我使用'php app / console ...'调用exec()以创建数据库,创建模式,然后删除数据库。 然而,这很慢,当我有一个以上的测试用例时它会一直发生。

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

我认为最好始终开始清洁以确保测试完全隔离。 要做到这一点,我只是在每次测试之前构建数据库结构,而不是用给定测试所需的夹具填充它。

请注意,我只构建所需的数据库表,而我只插入所需的灯具。 它比加载大型数据库转储要快一些。 它也更干净,因为测试不共享灯具(这使它们更容易维护)。

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

setUp()引导Symfony内核并在类属性中存储对它的引用(以及对DIC和实体管理器的引用)。 还调用generateSchema()来生成数据库模式(它使用Doctrine中的Schema Tool)。

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

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

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

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

对于测试用例,架构将仅创建/下载一次。

您还可以设置doctrine以使用inmemory sqlite数据库(速度非常快):

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

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

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

我开始使用SQLite内存数据库进行测试,并在每个测试用例之前重建db schema + inserted fixture。 这有两个主要缺点:

  • 它还是太慢了:(
  • 在dev&prod上我使用Mysql很快就成了一个问题,因为SQLite根本没有所需的所有功能,有时表现不同

在每次测试之前使用MSQL进行测试并重建架构+插入夹具太慢了。 所以我一直在寻找替代方案......

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

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

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

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

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

我已经使用这个捆绑已经有一段时间了,对我而言,它完全可以使用SQLite,MySQL或PostgreSQL。

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

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

结果是:

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

这是我的解决方案:

  1. 配置中的第二个parameters.yml配置为test
  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很难设置,但这确实是个好主意

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM