在 Laravel 6 中进行单元测试时处理模型关系 status/state 的最佳方式?
Best way to handle a model relationship status/state when unit testing in Laravel 6?
我在 Laravel 6.x 中使用 SQLite 进行了以下单元测试:
<?php
/** @var \Illuminate\Database\Eloquent\Factory $factory */
use App\Entry;
use App\EntryStatus;
use Faker\Generator as Faker;
$factory->define(Entry::class, function (Faker $faker) {
return [
'user_id' => 1,
'caption' => $faker->sentence(10),
'entry_status_id' => EntryStatus::where('name', 'pending')->first()->id,
];
});
$factory->state(Entry::class, 'awaiting_payment', [
'entry_status' => EntryStatus::where('name', 'awaiting_payment')->first()->id,
]);
我有一个'Trying to get 属性 'id' of non-object'的测试错误,这是针对以下行:
'entry_status' => EntryStatus::where('name', 'awaiting_payment')->first()->id,
我对如何修复此错误有一些想法,但我想知道在单元测试和 'The Laravel way'.
方面的最佳实践是什么
按照我的想法,我有一个 EntryStatus table,它有静态状态 'pending' => 0,'awaiting_payment' => 1,'paid' = > 2 等等。我在我的 App\Entry 模型中创建了一个关系 > App\EntryStatus。思路如下:
原计划;对于单元测试,每次测试我都需要为静态 EntryStatus table 设置种子。查看文档,我会使用类似 setUp() > $this->artisan('db:seed') 的东西。但这感觉真的会减慢测试速度。除非有一种方法可以在所有测试开始之前对数据库进行一次播种。
尝试创建一个创建静态数据的工厂('pending' => 0,'awaiting_payment' => 1)但我需要手动更新数据库种子和工厂每次都匹配这看起来很笨重。
在 Laravel 文档测试文档中有这个例子; $factory->state(App\User::class, 'delinquent', ['account_status' => 'delinquent',]).这让我觉得我可以完全删除关系 table EntryStatus 并只使用 Entry 中的字符串列来表示状态。我认为这将是最好的解决方案,但我担心我们使用 id 作为状态是有原因的,因为我认为它们在搜索查询中更快。但如果没有,我的雕像将被修复,这似乎是最 eloquent 的解决方案。
另一种选择是无论如何都将雕像存储为整数,记下什么状态是什么整数,但这似乎也不正确。
记录尚未创建,在工厂中以这种方式分配静态关系不是一个好主意。
您可以使用工厂 create
,然后在测试用例中分配关系。
例如:
Entry
工厂
$factory->define(Entry::class, function (Faker $faker) {
return [
'user_id' => factory(User)->create()->id,
'caption' => $faker->sentence(10),
'entry_status_id' => factory(EntryStatus)->create()->id,
];
});
EntryStatus
工厂
$factory->define(EntryStatus::class, function (Faker $faker) {
return [
'name' => $faker->word,
'entry_status' => $faker->numberBetween(0, 2) //Its better start from 1 though
];
});
User
工厂
$factory->define(User::class, function (Faker $faker) {
return [
'name' => $faker->word
];
});
在您的测试用例中开始将事物链接在一起(如果需要)。
/**
* @test
*/
public function exampleTestCase()
{
$enteryStatus = factory(EntryStatus::class)->create(['entry_status' => 1]);
//create 6 entries
$entry = factory(Entry::class, 6)->create(['entry_status_id' => $enteryStatus->id]);
//TODO: assert something
}
你可以查看afterCreatingState
$factory
->state(EntryStatus::class, 'awaiting_payment', ['name' => 'awaiting_payment'])
->afterCreatingState(EntryStatus::class, 'awaiting_payment', function ($entryStatus, $faker) {
factory(Entry::class)->create([
'entry_status_id' => $entryStatus->id,
]);
});
我在 Laravel 6.x 中使用 SQLite 进行了以下单元测试:
<?php
/** @var \Illuminate\Database\Eloquent\Factory $factory */
use App\Entry;
use App\EntryStatus;
use Faker\Generator as Faker;
$factory->define(Entry::class, function (Faker $faker) {
return [
'user_id' => 1,
'caption' => $faker->sentence(10),
'entry_status_id' => EntryStatus::where('name', 'pending')->first()->id,
];
});
$factory->state(Entry::class, 'awaiting_payment', [
'entry_status' => EntryStatus::where('name', 'awaiting_payment')->first()->id,
]);
我有一个'Trying to get 属性 'id' of non-object'的测试错误,这是针对以下行:
'entry_status' => EntryStatus::where('name', 'awaiting_payment')->first()->id,
我对如何修复此错误有一些想法,但我想知道在单元测试和 'The Laravel way'.
方面的最佳实践是什么按照我的想法,我有一个 EntryStatus table,它有静态状态 'pending' => 0,'awaiting_payment' => 1,'paid' = > 2 等等。我在我的 App\Entry 模型中创建了一个关系 > App\EntryStatus。思路如下:
原计划;对于单元测试,每次测试我都需要为静态 EntryStatus table 设置种子。查看文档,我会使用类似 setUp() > $this->artisan('db:seed') 的东西。但这感觉真的会减慢测试速度。除非有一种方法可以在所有测试开始之前对数据库进行一次播种。
尝试创建一个创建静态数据的工厂('pending' => 0,'awaiting_payment' => 1)但我需要手动更新数据库种子和工厂每次都匹配这看起来很笨重。
在 Laravel 文档测试文档中有这个例子; $factory->state(App\User::class, 'delinquent', ['account_status' => 'delinquent',]).这让我觉得我可以完全删除关系 table EntryStatus 并只使用 Entry 中的字符串列来表示状态。我认为这将是最好的解决方案,但我担心我们使用 id 作为状态是有原因的,因为我认为它们在搜索查询中更快。但如果没有,我的雕像将被修复,这似乎是最 eloquent 的解决方案。
另一种选择是无论如何都将雕像存储为整数,记下什么状态是什么整数,但这似乎也不正确。
记录尚未创建,在工厂中以这种方式分配静态关系不是一个好主意。
您可以使用工厂 create
,然后在测试用例中分配关系。
例如:
Entry
工厂
$factory->define(Entry::class, function (Faker $faker) {
return [
'user_id' => factory(User)->create()->id,
'caption' => $faker->sentence(10),
'entry_status_id' => factory(EntryStatus)->create()->id,
];
});
EntryStatus
工厂
$factory->define(EntryStatus::class, function (Faker $faker) {
return [
'name' => $faker->word,
'entry_status' => $faker->numberBetween(0, 2) //Its better start from 1 though
];
});
User
工厂
$factory->define(User::class, function (Faker $faker) {
return [
'name' => $faker->word
];
});
在您的测试用例中开始将事物链接在一起(如果需要)。
/**
* @test
*/
public function exampleTestCase()
{
$enteryStatus = factory(EntryStatus::class)->create(['entry_status' => 1]);
//create 6 entries
$entry = factory(Entry::class, 6)->create(['entry_status_id' => $enteryStatus->id]);
//TODO: assert something
}
你可以查看afterCreatingState
$factory
->state(EntryStatus::class, 'awaiting_payment', ['name' => 'awaiting_payment'])
->afterCreatingState(EntryStatus::class, 'awaiting_payment', function ($entryStatus, $faker) {
factory(Entry::class)->create([
'entry_status_id' => $entryStatus->id,
]);
});