Laravel工厂-动态创建或

时间:2020-03-05 08:16:27

标签: database laravel testing factory relation

我有一个简单的问题。

如何编写一个Factory,让我根据原始调用make()create()定义使用make()create()的关系?

这是我的用例:

我有一个简单的工厂

/** @var $factory Illuminate\Database\Eloquent\Factory */
$factory->define(App\User::class, function (Faker $faker) {
    return [
        'role_id' => factory(Role::class),
        'name' => $faker->name,
        'email' => $faker->unique()->safeEmail,
        'password' => 'secret',
    ];
});

我的问题是那个 role_id 。使用factory(Role::class)时,它将始终创建一个角色!用数据库编写...

在测试中,当我编写factory(User::class)->create();时,它将创建一个用户和角色,没关系!

但是如果我写factory(User::class)->make();仍会创建一个角色...使用make()时我不会在数据库中写一个角色,在那种情况下,我只想要一个简单的role_id => 0

我该如何实现?

谢谢!

编辑(解决方法)

好吧,这比预期的要难,当您定义嵌套关系时,没有办法知道何时使用make()create() ...我发现的唯一方法是使用{{1} }方法,然后查找从Factory调用的make方法。

为了简化和重用性,我为工厂创建了一个名为debug_stacktrace()的工厂助手方法,该方法将定义Factory中的关系。使用associateTo($class)时将返回相关模型的现有ID,使用create()时将返回1。

通过这种方式,工厂可以成为:

make()

助手功能是:

/** @var $factory Illuminate\Database\Eloquent\Factory */
$factory->define(App\User::class, function (Faker $faker) {
    return [
        'role_id' => associateTo(Role::class), // Defining relationship
        'name' => $faker->name,
        'email' => $faker->unique()->safeEmail,
        'password' => 'secret',
        'remember_token' => Str::random(10),
    ];
});

有了这个,我可以轻松地(使用工厂)编写单元测试,而无需使用数据库连接,因此单元测试变得非常快!

希望这对其他人有帮助!

2 个答案:

答案 0 :(得分:0)

您可以覆盖属性 role_id

factory(User::class)->make(['role_id' => 0]);

另一种解决方案-以_id结尾的任何属性的辅助方法:

function make($class)
{
    $attributes = \Schema::getColumnListing((new $class)->getTable());
    $exclude_attribures = [];

    foreach ($attributes as $attribute)
    {
        if(ends_with($attribute, '_id'))
        {
            $exclude_attribures[] = [$attribute => 0];
        }
    }

    return factory($class)->make($exclude_attribures);
}

通话示例:

make(User:class);

答案 1 :(得分:0)

您可以利用状态


/** @var $factory Illuminate\Database\Eloquent\Factory */
$factory->define(App\User::class, function (Faker $faker) {
    return [
        'role_id' => factory(Role::class),
        'name' => $faker->name,
        'email' => $faker->unique()->safeEmail,
        'password' => 'secret',
    ];
});

$factory->state(App\User::class, 'withoutRelationship', [
    'role_id' => null,
    'another_id' => null,
]);

然后

factory(User::class)->state('withoutRelationship')->make();
相关问题