【问题标题】:Continuous Integration, best practice to input actual test data into database, using Propel ORM持续集成,将实际测试数据输入数据库的最佳实践,使用 Propel ORM
【发布时间】:2015-04-07 04:21:33
【问题描述】:

我使用 Propel ORM 复制表架构,以进行持续集成,但 Propel 只为我提供了一个完全充实的架构,它没有为我提供测试数据(或根本必要的基本数据)。

如何从具有版本控制的propel-gen Propel ORM 生态系统的实时/测试数据库中获取数据?

【问题讨论】:

  • @halfer 是的,我很想听听这个问题,因为我很高兴将 phpunit 与 codeship.io 一起使用。

标签: phpunit continuous-integration database-schema propel


【解决方案1】:

他们说根本不存在任何“最佳实践”——它是如此主观,以至于人们应该满足于几种“最佳实践”形式中的一种。我认为以下符合该标签的条件 - 最终它对我很有效。我已经使用 PHPUnit 大约一年了,也许在我的项目上从头开始使用了六个月。

这是我在 PHPUnit 引导阶段所做的工作的概要(在 phpunit.xml 中指定):

  • 删除并创建myproject_test 数据库
  • 在生成的 SQL 的迁移前副本上调用 insert-sql Propel 命令
  • 调用migrate Propel 命令
  • 扫描我的测试文件夹以查找构建类以设置测试,然后依次运行每个测试

手动插入 SQL 然后运行迁移的好处是迁移得到了真正彻底的测试。这特别方便,因为在开发中我有时会做一个down,修改一个迁移类,然后做一个up 来重新运行它:因此知道它会按顺序运行是令人放心的。目前我打算永久保留我所有的迁移历史;虽然它会给测试和新版本增加非常小的延迟,但升级部署不会受到影响。

由于我的构建依赖于旧的 SQL 文件,因此我避免使用 sql 生成命令;如果它是意外发出的,修改后的 SQL 文件可以在版本控制中轻松恢复。

目前我只是在localhost上使用myproject_test的数据库名称,这样无论在哪里运行测试,其他数据库都不受影响。在构建服务器上,您可能需要使用不同的凭据进行连接:考虑在 switch() 语句中检测机器名称,并相应地选择连接详细信息。

为了给您提供测试数据,我通常倾向于建议您不要使用实时系统中的数据导出。对于一个人来说,它通常太多了,而且您通常希望为每个测试创建数据片段,以便测试完全隔离。我认为这是一个好主意,原因有两个:

  • 您可以并行化独立的测试。因此,当您的浏览器测试套件需要五个小时才能运行(!)时,您可以设置更多构建服务器以更快地获得绿色构建。
  • 您可能希望在本地单独运行一个测试套件,或者单独运行一个测试,或者一组匹配某个字符串的测试,如果一个测试依赖于另一个测试,这可能不起作用。

这是我的构建器类的用武之地。我在我的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");
        }
    }
}

!CommonBuild.php 中我添加了不会被测试修改的只读数据,因此只有一个副本是安全的。

每个 PHPUnit 测试类都有一个构建类:对于我拥有的每个 *Test.php 文件,我都会有一个对应的 *Build.php。在每个构建器中,都会调用一个build 静态方法,并且我为每个需要构建的测试手动运行一个方法。这是一个简单的:

public static function build()
{
    self::buildWriteVarToFieldSuccessfully();
    self::buildWriteVarToFieldUsingFailedMatch();
    self::buildWriteVarToFieldUsingFoundMatch();
    self::buildFailIfVariableIsAnArray();
}

在未来的某个时候,我可能会使用反射来自动运行这些,就像 PHPUnit 用于测试一样,但现在还可以。

现在,在我的引导脚本中,我使用测试连接完全初始化 Propel,因此普通的 Propel 语句可用。因此,我将只创建我需要的数据,如下所示:

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 测试中使用 setUp 方法做一些聪明的事情,检测当前测试(如果可能),然后运行适当的构建类。

【讨论】:

  • 嗯,我会检查一下,看看这个过程是否符合我的需要,谢谢。
  • 不幸的是,另外前几天我很好奇propel的发展情况,发现库的活动似乎已经逐渐减少,并且逐渐变成了一个无人维护的软件库,这意味着我实际上可能不得不完全重新考虑我最初使用推进的方法:github.com/propelorm/Propel/graphs/contributors
  • (这个答案引起了更多关注,因为我已经从一个新的类似问题中链接到它。我应该最感兴趣的是人们关于他们是否使用它或计划使用它的任何反馈读过它,或者关于我没有发现的缺点)。
  • Kzqai - 相信你看错了项目的版本 - 最新的是版本2:github.com/propelorm/Propel2/graphs/contributors
  • 是的,我确实最终发现他们已经创建了一个新的 Propel2 存储库,而版本 1 的 propel 存储库目前没有提到 propel2 存储库(还没有?)。
猜你喜欢
  • 2016-04-04
  • 1970-01-01
  • 2010-11-06
  • 1970-01-01
  • 2013-12-06
  • 2012-02-24
  • 1970-01-01
  • 2019-03-18
相关资源
最近更新 更多