nirnanaaa/testdummy

简单的测试存根

2.3.4 2016-07-13 09:31 UTC

README

TestDummy 将准备工厂(模拟数据)的过程简化到尽可能简单。就像...

使用模拟属性构建 Post 模型。

use Laracasts\TestDummy\Factory;

$post = Factory::build('Post');

如果我们然后执行 $post->toArray(),这可能会返回

array(4) {
  ["title"]=>
  string(21) "The Title of the Post"
  ["author_id"]=>
  string(1) "5"
  ["body"]=>
  string(226) "Iusto qui optio et iste. Cumque aliquid et omnis enim. Nesciunt ad esse a reiciendis expedita quidem veritatis. Nostrum repellendus reiciendis distinctio amet sapiente. Eum molestias a recusandae modi aut et adipisci corrupti."
  ["publish_date"]=>
  string(19) "2014-03-02 11:05:48"
}

构建一个帖子,但覆盖默认标题。

use Laracasts\TestDummy\Factory;

$post = Factory::build('Post', ['title' => 'Override Title']);

同样,当转换为数组...

array(4) {
  ["title"]=>
  string(14) "Override Title"
  ["author_id"]=>
  string(1) "5"
  ["body"]=>
  string(254) "In eos porro qui est rerum possimus voluptatem non. Repudiandae eaque nostrum eaque aut deleniti possimus quod minus. Molestiae commodi odit sunt dignissimos corrupti repudiandae quibusdam quo. Autem maxime tenetur autem corporis aut quis sint occaecati."
  ["publish_date"]=>
  string(19) "2013-06-24 10:01:30"
}

构建模型属性的数组。

$post = Factory::attributesFor('Post');

build()attributesFor() 的区别在于前者将返回给定模型类型的实例(如 Post)。后者将简单地返回生成的属性数组,这在某些情况下可能很有用。

构建并持久化一个歌曲实体。

use Laracasts\TestDummy\Factory;

$song = Factory::create('Song');

创建并持久化三个评论。

use Laracasts\TestDummy\Factory;

Factory::times(3)->create('Comment');

实际上,这将使你的 comments 表中有三行。如果该表有关系(如拥有帖子),这些相关行也将用模拟数据创建。

用法

步骤 1:安装

像任何其他包一样,通过 Composer 拉取此包。

"require-dev": {
    "laracasts/testdummy": "~2.0"
}

步骤 2:创建一个工厂文件

TestDummy 并不是魔法。您需要描述应生成的数据类型。

tests/factories 目录中,您可以创建任意数量的 PHP 文件,这些文件将由 TestDummy 自动加载。为什么不从通用的 tests/factories/factories.php 文件开始呢。

您创建的每个工厂文件都将自动访问两个变量

  • $factory
  • $faker

$factory 是您将用于定义新数据集的函数,例如 Post 或 Album 的构成。

$factory('Album', [
    'name' => 'Rock or Bust',
    'artist' => 'AC/DC'
]);

将这视为您未来生成专辑的定义 - 例如,当您这样做时

use Laracasts\TestDummy\Factory;

$album = Factory::create('Album');

Faker

您可能不希望为各种工厂硬编码字符串。使用随机数据会更容易更快。TestDummy 引入了出色的 Faker 库来协助此操作。

实际上,您的 tests/factories/ 目录中的任何文件都将自动访问一个 $faker 对象,您可以使用它。以下是一个示例

$factory('Comment', [
    'body' => $faker->sentence
]);

现在,每次生成一个新评论时,body 字段将被设置为随机句子。请参阅 Faker 文档以获取大量可用的假数据。

关系

如果您希望,TestDummy 还可以自动生成您的关系模型。您只需要让 TestDummy 知道其关联模型类型。TestDummy 然后将自动为您构建和保存该关系!

使用上面提到的 Comment 示例,一个评论属于用户,这是合理的,对吧?让我们设置它

$factory('Comment', [
    'user_id' => 'factory:User',
    'body' => $faker->sentence
]);

就是这样!注意这里的特殊语法:“factory:”,后面跟关联类/模型的名称。

为了用另一个示例说明这一点,如果一个歌曲属于专辑,而一个专辑属于艺术家,那么我们可以轻松表示这一点

$factory('App\Song', [
    'album_id' => 'factory:App\Album',
    'name' => $faker->sentence
]);

$factory('App\Album', [
    'artist_id' => 'factory:App\Artist',
    'name' => $faker->word
]);

$factory('App\Artist', [
    'name' => $faker->word
]);

所以这里很酷的事情是:这一切都将递归工作。换句话说,如果您这样做...

use Laracasts\TestDummy\Factory;

$song = Factory::create('App\Song');

...那么 TestDummy 不仅会在数据库中构建和持久化一个歌曲,还会构建和持久化相关的专辑及其相关的艺术家。很酷!

自定义工厂

到目前为止,你已经学习了如何使用类名生成数据,例如 App\User。然而,有时你可能需要为测试目的定义多种用户类型。

虽然可以使用覆盖,如下所示

Factory::create('App\User', ['role' => 'admin']);

...如果这是你经常要做的事情,创建一个自定义工厂,如下所示

// A generic factory for users...

$factory('App\User', [
    'username' => $faker->username,
    'password' => $faker->password,
    'role'     => 'member'
]);

// And a custom one for administrators

$factory('App\User', 'admin_user', [
    'username' => $faker->username,
    'password' => $faker->password,
    'role'     => 'admin'
]);

在上面的代码片段中,你已经熟悉了第一个例子。对于第二个例子,请注意,我们为这种特殊类型的用户工厂添加了一个“简称”或标识符。现在,每当你想要快速生成一个管理员用户时,你可以这样做

use Laracasts\TestDummy\Factory;

$adminUser = Factory::create('admin_user');

使用闭包定义

或者,你也可以将闭包作为第二个参数传递给 $factory 方法。这在需要更多控制每个属性所赋值的情况很有用。以下是一个示例

$factory('App\Artist', function($faker) {
    $name = sprintf('Some Band Named %s', $faker->word);
    
    return [
        'name' => $name
    ];
});

当然,请确保从这个闭包中返回一个数组。如果不这样做,将会抛出异常。

步骤 3:设置

在测试数据库时,建议每个测试使用完全相同的数据库环境和结构。这样,你可以防止出现假阳性。在这种情况下,SQLite数据库(甚至是一个内存中的数据库)是一个不错的选择。

public function setUp()
{
    parent::setUp();

    Artisan::call('migrate');
}

或者,如果无法使用内存中的数据库,为了节省时间,这个包包含了辅助类 Laracasts\TestDummy\DbTestCase。如果你扩展它,在每个测试之前,你的测试数据库将进行迁移(如果需要),并且所有数据库更改将通过事务进行,然后在 tearDown 中回滚。这将提高速度,并确保所有测试都以相同的数据库结构开始。

use Laracasts\TestDummy\DbTestCase;

class ExampleTest extends DbTestCase {

    /** @test */
    function it_does_something()
    {
        // Before each test, your database will be rolled back
    }
}

步骤 4:编写您的测试

你现在可以开始了。开始测试!以下是一些可以帮助你开始的代码。假设你已经创建了一个 PostComment 模型...

use Laracasts\TestDummy\Factory;

$comment = Factory::create('Comment');

这将创建并保存数据库中的 CommentPost 记录。

或者,也许你需要编写一个测试来确保,如果你有三个带相应长度的歌曲,当你在拥有者 Album 模型上调用 getTotalLength 方法时,它将返回正确的值。这很简单!

// create three songs, and explicitly set the length
Factory::times(3)->create('Song', ['length' => 200]);

$album = Album::first(); // this will be created once automatically.

$this->assertEquals(600, $album->getTotalLength());

当然,现在请确保你在某个工厂文件中注册了 SongAlbum 的定义,然后你就可以开始了!

// tests/factories/factories.php

$factory('Song', [
  'album_id' => 'factory:Album',
  'name' => $faker->sentence
]);

$factory('Album', [
  'name' => $faker->sentence
]);

常见问题解答

如何指定不同的工厂文件夹?

很简单。在测试运行之前,添加以下代码

Factory::$factoriesPath = 'app/tests/factories';

现在,TestDummy 将在 app/tests/factories 文件夹中寻找你的注册工厂。

我想控制我的模型是如何构建和保存的...

好的,只需创建你自己的 Laracasts\TestDummy\IsPersistable 实现即可。这个合约由一些你需要实现的方法组成。

一旦你有你的实现,在测试运行之前,添加以下代码

Factory::$databaseProvider = new MyCustomBuilder;

这就完成了!现在,每当生成并保存一个实体时,TestDummy 将参考你的自定义实现。