Phpunit 持续集成,使用Propel ORM将实际测试数据输入数据库的最佳实践
我使用Propel ORM复制一个表模式,以便进行持续集成,但Propel只为我提供了一个完全充实的模式,它没有为我提供测试数据(或基本的必要数据) 如何从带有版本控制的propel gen(propel ORM生态系统)的实时/测试数据库中获取数据?他们说,任何东西都不存在“最佳实践”——这是一种主观的做法,人们应该满足于几种形式的“良好实践”中的一种。我认为下面的内容符合这个标签的要求,而且最终对我来说效果很好。我已经使用PHPUnit大约一年了,也许六个月都是从头开始的 下面是我在PHPUnit引导阶段所做工作的概要(在Phpunit 持续集成,使用Propel ORM将实际测试数据输入数据库的最佳实践,phpunit,continuous-integration,database-schema,propel,Phpunit,Continuous Integration,Database Schema,Propel,我使用Propel ORM复制一个表模式,以便进行持续集成,但Propel只为我提供了一个完全充实的模式,它没有为我提供测试数据(或基本的必要数据) 如何从带有版本控制的propel gen(propel ORM生态系统)的实时/测试数据库中获取数据?他们说,任何东西都不存在“最佳实践”——这是一种主观的做法,人们应该满足于几种形式的“良好实践”中的一种。我认为下面的内容符合这个标签的要求,而且最终对我来说效果很好。我已经使用PHPUnit大约一年了,也许六个月都是从头开始的 下面是我在PHPU
PHPUnit.xml
中指定):
- 删除并创建
数据库myproject\u测试
- 对生成的sql的预迁移副本调用
spreep命令insert sql
- 调用
spreep命令migrate
- 扫描我的测试文件夹中的生成类以设置测试,然后依次运行每个测试
向下
,修改迁移类,然后执行向上
重新运行它:因此,知道它将按顺序运行是令人放心的。目前,我计划永久保留我所有的移民历史;虽然这会给测试和新构建增加很小的延迟,但升级部署不会受到影响
因为我的构建依赖于一个旧的SQL文件,所以我避免使用SQL
generation命令;如果它是意外发出的,那么修改后的SQL文件可以在版本控制中轻松地恢复
目前,我只是在localhost
上使用一个数据库名myproject\u test
,这样无论在哪里运行测试,其他数据库都不会受到影响。在构建服务器上,您可能需要使用不同的凭据进行连接:考虑在<代码>开关()/<代码>语句中检测机器名称,并相应地选择连接细节。
为了给您提供要测试的数据,我通常倾向于建议您不要使用从实时系统导出的数据。首先,通常有太多的数据,而且您通常希望在每个测试中创建数据片段,以便测试完全隔离。我认为这是一个好主意,有两个原因:
- 您可以并行化独立的测试。因此,当您的浏览器测试套件运行五个小时(!)时,您可以设置更多构建服务器,以更快地获得绿色构建
- 您可能希望自己在本地运行一个测试套件,或者自己运行一个测试,或者运行一组匹配某个字符串的测试,如果一个测试依赖于另一个测试,那么这可能不起作用
bootstrap.php
中使用它,并在包含测试类的每个文件夹中调用它:
function runBuilders($buildFolder, $namespace)
{
// I use ! to mark common builders that need to be run first.
// Since this confuses autoloader, I load that manually.
$commonBuilder = $buildFolder . '/!CommonBuild.php';
if (file_exists($commonBuilder))
{
require_once $commonBuilder;
}
foreach(glob($buildFolder . '/*Build.php') as $class)
{
$matches = array();
$found = preg_match('#/([!a-zA-Z]+)\.php#', $class, $matches);
if ($found)
{
echo '.';
// Don't use ! characters when creating the class
$className = str_replace('!', '', $matches[1]);
call_user_func($namespace . "\\{$className}::build");
}
}
}
在中!php
我添加了不会被测试修改的只读数据,因此只有一个副本是安全的
每个PHPUnit测试类有一个构建类:对于我拥有的每个*test.php
文件,我将有一个相应的*build.php
。在每个构建器中,都会调用一个build
静态方法,这样我就可以为每个需要构建的测试手动运行一个方法。这里有一个简单的例子:
public static function build()
{
self::buildWriteVarToFieldSuccessfully();
self::buildWriteVarToFieldUsingFailedMatch();
self::buildWriteVarToFieldUsingFoundMatch();
self::buildFailIfVariableIsAnArray();
}
在将来的某个时候,我可能会使用反射来自动运行这些程序,就像PHPUnit对测试所做的那样,但现在还可以
现在,在我的引导脚本中,我使用测试连接完全初始化了推进,所以普通的推进语句可用。因此,我将创建所需的数据,如下所示:
protected static function buildWriteVarToFieldUsingFoundMatch()
{
// Save an item in the holding table
$employer = self::createEmployer();
$job = new \Job\Model\JobHolding();
$job->setReference('12345');
$job->setLocationAlias('Rhubarb patch');
$job->setEmployerId($employer->getPrimaryKey());
$job->save();
$process = self::createProcessingUsingRowMatching($employer);
$process->createSource('VarToFieldTest_buildWriteVarToFieldUsingFoundMatch');
}
我有一个命名约定,即测试类中的testWriteVarToFieldUsingFoundMatch
测试在相应的构建类中获得一个名为buildWriteVarToFieldUsingFoundMatch
的构建器。在代码中没有这样的强制,但这种命名有助于轻松找到给定的一个(我经常使用IDE的分屏功能同时编辑这两个)
因此,在上面的示例中,我只需要一个雇主记录、一个工作记录、一个流程记录和一个源记录来运行这个特定的测试(而不是整个实时导出)。源记录被赋予了一个与测试名称相关的唯一名称,因此它只会在这个测试中使用(我发现我必须注意这里的复制和粘贴错误-在测试中使用错误数据非常容易!)
创建这种类型的测试数据非常容易,无论您拥有何种类型的数据库:user.name
字段、address.line1
字段等等,通常都可以创建包含唯一标识符的字段,以便在测试中修改此数据时,您知道只有该测试才会使用它,因此,它与其他测试隔离开来
出于简单的原因,我选择在引导中运行所有构建器,而不管正在运行什么测试。因为这只需要额外15秒,在我的情况下,可能不值得做更复杂的事情。但是,如果您愿意,您可以在每个PHPUnit测试中使用
设置方法做一些聪明的事情,检测当前的测试(如果可能),然后运行适当的构建类。@halfer是的,我很乐意听到这方面的进展,因为我很高兴将PHPUnit与codeship.io.Hmmm一起使用,我会检查一下,看看这个过程是否符合我的需要,谢谢。不幸的是,另外几天前我对propel的开发状态很好奇,发现库上的活动似乎已经逐渐减少,它似乎正在逐渐变成一个未维护的软件库,这意味着我实际上可能不得不完全