本文介绍了持续集成,将实际测试数据输入数据库的最佳实践,使用 Propel ORM的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I used Propel ORM to duplicate a table schema, in order to do continuous integration, but Propel only gets me a fully fleshed out schema, it doesn't get me test data (or basic necessary data at all).

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

How do I get the data from a live/test database with a version controlled propel-gen Propel ORM ecosystem?

推荐答案

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

They say that "best practice" in anything at all doesn't exist - it's so subjective that one ought to settle for one of several forms of "good practice" instead. I think the below qualifies for that label — and ultimately it works well for me. I've been using PHPUnit for about a year, and perhaps for six months on my projects from scratch.

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

Here's a synopsis of what I do in the PHPUnit bootstrap phase (specified in phpunit.xml):

  • 删除并创建 myproject_test 数据库
  • 在生成的 SQL 的迁移前副本上调用 insert-sql Propel 命令
  • 调用migrate Propel 命令
  • 扫描我的测试文件夹以查找构建类以设置测试,然后依次运行每个测试
  • Drop and create the myproject_test database
  • Call the insert-sql Propel command on a pre-migrations copy of the generated SQL
  • Call the migrate Propel command
  • Scan my test folders for build classes to set up the tests, and run each in turn

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

The benefit of inserting SQL manually and then running migrations is that migrations get a really thorough testing. This is especially handy since in development I sometimes will do a down, modify a migration class, then do an up to re-run it: it is therefore reassuring to know it will run in order. At present I plan to keep all of my migration history permanently; whilst it will add very minor delay to testing and new builds, upgrade deployments won't be affected.

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

Since my build depends on having an old SQL file, I avoid using the sql generation command; if it is accidentally issued, the modified SQL files can be trivially reverted in version control.

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

At present, I am simply using a database name of myproject_test on localhost, so that wherever the tests are run, other database are not affected. It is possible that on build servers you will be required to connect using different credentials: consider detecting the machine name in a switch() statement, and selecting the connection details accordingly.

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

To give you data to test, I am generally inclined to recommend you don't use an export of data from your live system. There's usually too much of it, for one, and also you generally want to create pieces of data per test, so that tests are completely isolated. I think this is a good idea for two reasons:

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

这是我的构建器类进来的地方.我在我的 bootstrap.php 中使用它并在每个包含测试类的文件夹上调用它:

This is where my builder classes come in. I use this in my bootstrap.php and call it on each folder containing test classes:

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 中我添加了不会被测试修改的只读数据,因此只有一份是安全的.

In !CommonBuild.php I add read-only data that won't be modified by tests, and so it is safe to have just one copy.

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

I have one build class per PHPUnit test class: for every *Test.php file I have, I will have a corresponding *Build.php. In each builder, a build static method is called, and in that I manually run a method for each test that needs something built. Here is a simple one:

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

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

At some point in the future I'll probably use Reflection to run these automatically, like PHPUnit does for tests, but it is fine for now.

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

Now, in my bootstrap script I fully initialise Propel, using the test connection, so ordinary Propel statements are available. I will thus create just the data I need, like so:

protected static function buildWriteVarToFieldUsingFoundMatch()
{
    // Save an item in the holding table
    $employer = self::createEmployer();
    $job = new JobModelJobHolding();
    $job->setReference('12345');
    $job->setLocationAlias('Rhubarb patch');
    $job->setEmployerId($employer->getPrimaryKey());
    $job->save();

    $process = self::createProcessingUsingRowMatching($employer);
    $process->createSource('VarToFieldTest_buildWriteVarToFieldUsingFoundMatch');
}

我有一个命名约定,即测试类中的 testWriteVarToFieldUsingFoundMatch 测试会在相应的构建类中获得一个名为 buildWriteVarToFieldUsingFoundMatch 的构建器.它在代码中并未强制执行,但这种命名有助于轻松找到一个给定另一个(我经常使用我的 IDE 的分屏功能同时编辑两者).

I have a naming convention that a test of testWriteVarToFieldUsingFoundMatch in a test class gets a builder called buildWriteVarToFieldUsingFoundMatch in the corresponding build class. It's not enforced as such in code, but this naming helps find one given the other easily (I will often edit both at the same time, using my IDE's split screen feature).

因此,在上面的示例中,我只需要一个雇主记录、一个工作记录、一个流程记录和一个源记录来运行这个特定的测试(而不是整个实时导出).源记录被赋予一个与测试名称相关的唯一名称,因此它只会在这个测试中使用(我发现我必须注意这里的复制和粘贴错误 - 它很容易使用测试中有错误的数据!).

So, in the example above, I only needed one employer record, one job record, one process record and one source record to run this particular test (and not a whole live export). The source record is given a unique name relating to the test name, so that it will only be used in this test (I've found I have to watch out for copy-and-paste errors here - it is quite easy to use the wrong data in a test!).

创建这种类型的测试数据很容易,无论你有什么类型的数据库:user.name 字段,address.line1 字段等等通常都可以创建包含唯一标识符,因此当您在测试中修改此数据时,您知道只有该测试会使用它,因此它与其他测试隔离.

Creating test data of this kind is quite easy, whatever kind of database you have: user.name fields, address.line1 fields and so forth can usually be created containing a unique identifier, so that when you modify this data in a test, you know that only that test is going to use it, and thus that it is isolated from other tests.

为了简单起见,无论正在运行什么测试,我都选择在引导程序中运行所有构建器.由于这只需要额外的 15 秒,就我而言,可能不值得做更复杂的事情.但是,如果您愿意,您可以在每个 PHPUnit 测试中使用 setUp 方法做一些聪明的事情,检测当前测试(如果可能),然后运行适当的构建类.

I've opted to run all builders in the bootstrap regardless of what tests are being run, for reasons of simplicity. Since this takes only 15 extra seconds, in my case it's probably not worth doing something more complicated. However, if you wish, you could do something clever with the setUp method in each PHPUnit test, detect the current test (if possible) and then run the appropriate build class.

这篇关于持续集成,将实际测试数据输入数据库的最佳实践,使用 Propel ORM的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

06-05 02:22
查看更多