zizaco / factory-muff
Requires
- php: >=5.4.0
Requires (Dev)
- doctrine/orm: ^2.5
- illuminate/database: 5.0.* || 5.1.* || 5.5.* || ^6.0
- league/factory-muffin-faker: ^2.3
- phpunit/phpunit: ^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20
Suggests
- doctrine/orm: Factory Muffin supports doctrine through the repository store.
- illuminate/database: Factory Muffin supports eloquent through the model store.
- league/factory-muffin-faker: Factory Muffin is very powerful together with faker.
Replaces
- zizaco/factory-muff: v3.3.0
This package is auto-updated.
Last update: 2022-01-17 17:20:08 UTC
README
此包的目标是能够快速创建对象,以便进行测试。
它基本上是一个 "factory_girl",为PHP简化使用。
安装
在您的 composer.json 中,只需将 "league/factory-muffin": "^3.3"
添加到您的 "require-dev"
部分
{ "require-dev": { "league/factory-muffin": "^3.3" } }
Faker 支持由 Factory Muffin Faker 提供。如果您想启用 Faker 支持,则需要添加 "league/factory-muffin-faker": "^2.3"
也是
{ "require-dev": { "league/factory-muffin": "^3.3", "league/factory-muffin-faker": "^2.3" } }
升级
现有用户查看 升级指南 可能会有所帮助。
使用
介绍
这是 Factory Muffin 3.0 的使用指南。在本指南中,您将看到 "the xyz
函数可以调用"。您应该假设这些函数应该在 League\FactoryMuffin\FactoryMuffin
的实例上调用;您应该自己跟踪此实例,当然,您可以为最大灵活性拥有多个此类的实例。为了简单起见,我们的大多数示例都包括一个 $fm
变量。当使用 loadFactories
函数引入文件时,此变量实际上会可用。
模型定义
您可以使用 define
函数定义模型生成器。您可以这样调用它:$fm->define('Fully\Qualifed\ModelName')->addDefinitions('foo', 'bar')
,其中 foo
是您希望在模型上设置的属性名称,而 bar
描述了您希望如何生成该属性。您也可以一次性定义多个属性,如下所示:$fm->define('Fully\Qualifed\ModelName')->setDefinitions('foo', 'bar')
。请注意,这两个函数都追加到内部属性定义数组,而不是替换它。有关更多信息,请参阅生成器部分。
您还可以为您的模型定义多个不同的模型定义。您可以通过在模型类名称前加上您的 "group" 并跟一个冒号来实现这一点。这会导致您以这种方式定义模型:$fm->define('myGroup:Fully\Qualifed\ModelName')->addDefinitions('bar', 'baz')
。您不需要在这里完全定义模型,因为我们首先会寻找不带 group 前缀的定义,然后应用您的 group 定义,在需要时覆盖属性定义。请注意,如果您想使用 group 前缀,必须 还创建一个不带 group 前缀的定义。
我们为您提供了在测试中实现此功能的一种巧妙方法。PHPUnit 提供了 setupBeforeClass
函数。在该函数内部,您可以调用 $fm->loadFactories(__DIR__ . '/factories');
,这将包含工厂文件夹中的所有文件。在这些 PHP 文件中,您可以放置您的定义(调用 define 函数的所有代码)。
loadFactories
函数将遍历您指定的路径下的所有子文件夹以查找工厂文件,除了隐藏文件夹(即以 . 开头的文件夹)将被忽略。如果找不到您指定的工厂目录,它将抛出 League\FactoryMuffin\Exceptions\DirectoryNotFoundException
异常。
创建/实例化回调
您可以使用 setCallback
函数指定在模型创建/实例化时执行的回调,例如:$fm->define('MyModel')->setCallback(function ($object, $saved) {})
。我们将把您的模型实例作为回调的第一个参数传递,并将布尔值作为第二个参数。布尔值将为 true
如果模型正被持久化到数据库(使用了 create 函数),否则为 false
(使用了 instance 函数)。我们在底层使用的是 isPendingOrSaved
函数。请注意,如果您指定了回调并使用了 create
函数,我们将在执行回调前后尝试将您的模型保存到数据库。
生成器
可调用
如果需要更定制的解决方案,可以使用可调用生成器。您从闭包返回的任何内容,或有效的可调用内容,都将被设置为属性。闭包/可调用将以与上述创建/实例化回调相同的参数调用:您的模型实例作为第一个参数(以便您有更大的灵活性来按需修改它)和一个表示模型是否正被持久化到数据库的布尔值。在下面的示例中,我们将介绍如何使用闭包或可调用,以及如何使用 faker 生成属性。
示例 1
如您从本例中看到的,使用闭包生成属性的能力非常有用且灵活。这里我们使用它根据最初随机生成的 5 个词长的标题生成一个 slug。
$fm->define('MyModel')->setDefinitions([ 'title' => Faker::sentence(5), 'slug' => function ($object, $saved) { $slug = preg_replace("/[^a-zA-Z0-9\/_|+ -]/", '', $object->title); $slug = strtolower(trim($slug, '-')); $slug = preg_replace("/[\/_|+ -]+/", '-', $slug); return $slug; }, ]);
示例 2
这将把 foo
属性设置为调用 MyModel::exampleMethod($object, $saved)
返回的内容。
$fm->define('MyModel')->setDefinitions([ 'foo' => 'MyModel::exampleMethod', ]);
示例 3
这是一个使用我们伪造包装器设置几个不同属性的简单示例。
use League\FactoryMuffin\Faker\Facade as Faker; $fm->define('MyModel')->setDefinitions([ 'foo' => Faker::word(), // Set the foo attribute to a random word 'name' => Faker::firstNameMale(), // Set the name attribute to a random male first name 'email' => Faker::email(), // Set the email attribute to a random email address 'body' => Faker::text(), // Set the body attribute to a random string of text 'slogan' => Faker::sentence(), // Set the slogan attribute to a random sentence ]);
示例 4
这将把 age
属性设置为介于 20 和 40 之间的随机数。
use League\FactoryMuffin\Faker\Facade as Faker; $fm->define('MyModel')->setDefinitions([ 'age' => Faker::numberBetween(20, 40), ]);
示例 5
这将把 name
属性设置为随机的女性名字。因为我们首先调用了 unique
方法,所以属性应该在所有生成的模型之间是唯一的。如果您正在生成很多模型,请小心使用此方法,因为我们可能会用尽唯一的项。另外,请注意,调用 Faker::setLocale('whatever')
将重置内部的唯一列表。
use League\FactoryMuffin\Faker\Facade as Faker; $fm->define('MyModel')->addDefinition('name', Faker::unique()->firstNameFemale());
示例 6
这将设置 profile_pic
属性为随机图像 URL,尺寸为 400x400。因为我们首先调用了 optional
方法,所以并非所有生成的模型都会设置图像 URL;有时我们会返回 null。
use League\FactoryMuffin\Faker\Facade as Faker; $fm->define('MyModel')->addDefinition('profile_pic', Faker::optional()->imageUrl(400, 400));
更多
查看faker 库本身以了解所有可用方法。这里要涵盖的方法太多,它们自己的文档中也是如此。注意,如果您想调整底层 faker 实例,可以通过我们 faker 类的公共方法来实现。
工厂
工厂生成器可以用来设置模型之间的关系。工厂生成器将返回您要求其生成的模型的模型 ID。
示例 1
当我们创建一个 Foo 对象时,我们会发现 Bar 对象也会被生成并保存,并且它的 ID 将被分配给 Foo 模型的 bar_id
属性。
$fm->define('Foo')->addDefinition('bar_id', 'factory|Bar'); $fm->define('Bar')->addDefinition('baz', Faker::date('Y-m-d'));
创建和播种
create
函数将创建并保存您的模型,并且还会保存您使用 Factory
生成器生成的任何内容。如果您想创建多个实例,请查看 seed
函数,该函数在开始时接受一个额外的参数,即要生成的模型数量。该 seed
函数将重复调用 create
函数。
例如,让我们创建一个用户模型,并将其与多个位置和电子邮件模型关联。每个电子邮件也将有多个标记模型。
$user = $fm->create('User'); $profiles = $fm->seed(5, 'Location', ['user_id' => $user->id]); $emails = $fm->seed(100, 'Email', ['user_id' => $user->id]); foreach ($emails as $email) { $tokens = $fm->seed(50, 'Token', ['email_id' => $email->id]); }
您可能会遇到以下异常
- 如果定义的模型类找不到,将抛出
League\FactoryMuffin\Exceptions\ModelNotFoundException
。 - 如果您尝试创建一个模型但尚未为其定义模型定义,将抛出
League\FactoryMuffin\Exceptions\DefinitionNotFoundException
。 - 如果您的模型上的保存函数返回 false,将抛出
League\FactoryMuffin\Exceptions\SaveFailedException
。 - 如果您的模型上的保存函数不存在,将抛出
League\FactoryMuffin\Exceptions\SaveMethodNotFoundException
。 - 在尝试创建或保存模型时,您的模型可能抛出的任何其他异常。
还有 5 个其他辅助函数可用
- 您可以使用
pending
返回所有等待保存的对象数组。 - 您可以使用
isPending
与一个模型实例一起调用,以检查它是否会保存。 - 您可以使用
saved
返回所有已保存的对象数组。 - 您可以使用
isSaved
与一个模型实例一起调用,以检查它是否已保存。 - 您可以使用
isPendingOrSaved
与一个模型实例一起调用,以检查它是否会保存或已保存。
另外,如果您不想使用数据库持久性,instance
函数仍然可用。
删除
您可以使用 deleteSaved
函数删除所有已保存的模型。请注意,您的已保存模型将按保存的顺序删除,以确保关系行为正确。
如果无法删除一个或多个模型,在我们尝试删除所有已保存模型之后,将引发 League\FactoryMuffin\Exceptions\DeletingFailedException
。您可以通过 getExceptions
函数访问每个底层异常,该函数将返回一个异常数组。您可能会遇到以下异常
- 如果您的模型上的删除函数返回false,将抛出
League\FactoryMuffin\Exceptions\DeleteFailedException
。 - 如果您的模型上不存在删除函数,将抛出
League\FactoryMuffin\Exceptions\DeleteMethodNotFoundException
。 - 在尝试删除模型时,您的模型抛出的任何其他异常。
建议您从PHPUnit的tearDownAfterClass
函数中调用deleteSaved
函数,但是,如果您正在使用Laravel的TestCase
编写测试,您应该在调用parent::tearDown
之前从tearDown
方法中调用deleteSaved
函数。此方法会刷新应用程序实例的绑定,Factory Muffin将无法执行其删除操作。此外,这将解除分配的异常处理程序,您将无法通过绑定解析异常来调试测试,从而模糊了真正的异常。
实际示例
首先,我们需要创建一些定义
# tests/factories/all.php use League\FactoryMuffin\Faker\Facade as Faker; $fm->define('Message')->setDefinitions([ 'user_id' => 'factory|User', 'subject' => Faker::sentence(), 'message' => Faker::text(), 'phone_number' => Faker::randomNumber(8), 'created' => Faker::date('Ymd h:s'), 'slug' => 'Message::makeSlug', ])->setCallback(function ($object, $saved) { // we're taking advantage of the callback functionality here $object->message .= '!'; }); $fm->define('User')->setDefinitions([ 'username' => Faker::firstNameMale(), 'email' => Faker::email(), 'avatar' => Faker::imageUrl(400, 600), 'greeting' => 'RandomGreeting::get', 'four' => function() { return 2 + 2; }, ]);
然后您可以在测试中使用这些工厂
# tests/TestUserModel.php use League\FactoryMuffin\Faker\Facade as Faker; class TestUserModel extends PHPUnit_Framework_TestCase { protected static $fm; public static function setupBeforeClass() { // create a new factory muffin instance static::$fm = new FactoryMuffin(); // you can customize the save/delete methods // new FactoryMuffin(new ModelStore('save', 'delete')); // load your model definitions static::$fm->loadFactories(__DIR__.'/factories'); // you can optionally set the faker locale Faker::setLocale('en_EN'); } public function testSampleFactory() { $message = static::$fm->create('Message'); $this->assertInstanceOf('Message', $message); $this->assertInstanceOf('User', $message->user); } public static function tearDownAfterClass() { static::$fm->deleteSaved(); } }
更多信息
如果您想了解更多信息,以下资源可供您参考
- 生成的API文档可在这里找到。
- Philip Brown的文章可在这里找到。
- 我们的测试套件也可能对您有用。
集成
贡献
请查看我们的贡献指南以获取详细信息。
鸣谢
Factory Muffin基于Zizaco Zizuini在“Factory Muff”上的原始工作,并由Graham Campbell维护。在3.0版本发布之前,Scott Robertson也是共同维护者。感谢我们所有优秀的贡献者。
安全
如果您在此软件包中发现安全漏洞,请向Graham Campbell发送电子邮件至[email protected]。所有安全漏洞都将得到及时处理。您可以在此处查看我们的完整安全政策。
许可
Factory Muffin采用MIT许可证(MIT)。
企业版
作为Tidelift订阅的一部分提供
《league/factory-muffin》及其他数千个包的维护者正在与Tidelift合作,为构建应用程序所使用的开源依赖项提供商业支持和维护。节省时间、降低风险,同时为使用的确切的依赖项支付维护者的费用。了解更多信息。点击这里