目前测试数据库与 Symfony2 交互的最佳实践是什么?我有一个简单的 CRUD 设置,我想确保我的测试正常。现在,我有 4 个测试,每个测试都确保创建、更新、删除和列出操作正常。
在我的测试用例中,我有两个魔术方法,__construct 和 __destruct。在它们内部,我使用 'php app/console ...' 调用 exec() 以创建数据库、创建模式并稍后删除数据库。但是,这太慢了,当我有多个测试用例时,它总是会发生。
在进行数据库测试和隔离此类测试时,我应该如何进行?
目前测试数据库与 Symfony2 交互的最佳实践是什么?我有一个简单的 CRUD 设置,我想确保我的测试正常。现在,我有 4 个测试,每个测试都确保创建、更新、删除和列出操作正常。
在我的测试用例中,我有两个魔术方法,__construct 和 __destruct。在它们内部,我使用 'php app/console ...' 调用 exec() 以创建数据库、创建模式并稍后删除数据库。但是,这太慢了,当我有多个测试用例时,它总是会发生。
在进行数据库测试和隔离此类测试时,我应该如何进行?
我认为最好始终从清洁开始,以确保测试完全隔离。为此,我只是在每次测试之前构建数据库结构,然后用给定测试所需的固定装置填充它。
请注意,我只构建所需的数据库表,并且只插入所需的固定装置。它比加载大型数据库转储快一点。它也更干净,因为测试不共享固定装置(这使它们更容易维护)。
我有一个名为 KernelAwareTest 的基本测试用例类,它可以帮助我构建模式。您可以在 gist 上找到它:https ://gist.github.com/1319290
setUp()启动 Symfony 内核并将对它的引用存储在类属性中(连同对 DIC 和实体管理器的引用)。还调用generateSchema()生成数据库模式(它使用 Doctrine 中的模式工具)。
默认情况下,它为实体管理器已知的所有实体生成数据库结构。getMetadatas()您可以通过覆盖该方法在测试类中更改此行为。
PS:我尝试使用内存数据库(sqlite),但并不完美。无论如何,对您在生产中使用的数据库运行测试可能会更好。
数据库测试总是很慢,因为您需要在每次测试之前/之后创建/删除架构。为避免不必要的操作,您可以:
模式只会为您的测试用例创建/删除一次。
您还可以设置学说以使用 inmemory sqlite 数据库(非常快):
doctrine:
dbal:
driver: pdo_sqlite
path: :memory:
memory: true
无论如何,'_ construct'和' _destruct'不应该在phpunit测试用例中使用,而应该使用'setUp'和'tearDown'。
这个问题已经很老了,但今天仍然有效,所以这是我的经验以及我今天在 Symfony 项目中如何处理它。
我开始使用 SQLite 内存数据库进行测试,并在每个测试用例之前重建 db 模式 + 插入的固定装置。这有两个主要缺点:
使用 MSQL 进行测试并在每次测试之前重建模式 + 插入固定装置太慢了。所以我一直在寻找替代品...
我偶然发现了这篇博文: http: //alexandre-salome.fr/blog/Symfony2-Isolation-Of-Tests
这里的人建议在活动数据库事务中运行测试,并在每次测试后简单地回滚任何更改。
我接受了这个想法并为它创建了一个包:https ://github.com/dmaicher/doctrine-test-bundle
捆绑包的设置非常简单,不需要更改任何现有的 php 测试类。在内部,它更改了学说配置以使用自定义数据库连接 + 驱动程序。
使用这个包,您可以在运行整个测试套件之前简单地创建数据库模式 + 插入固定装置(我更喜欢在自定义 phpunit 引导文件中执行此操作)。使用 phpunit 侦听器,所有测试都将在数据库事务中运行。
我已经使用这个包已经有一段时间了,对我来说,使用 SQLite、MySQL 或 PostgreSQL 可以完美地工作。
一段时间以来,它也用于 symfony-demo 项目。
在本地机器上测试是痛苦的......,所以我开始使用 ci 系统 buddy.works(有免费的独立版本),为此我需要自己解决这个问题。
结果是:
这是我的解决方案:
/**
* 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 很难设置,但这确实是个好主意