我在Laravel 6.x中使用SQLite进行了以下单元测试:
<?php
/** @var IlluminateDatabaseEloquentFactory $factory */
use AppEntry;
use AppEntryStatus;
use FakerGenerator 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,
]);
我有一个测试错误"尝试获取非对象的属性"id",这是针对以下行的:
'entry_status' => EntryStatus::where('name', 'awaiting_payment')->first()->id,
关于如何修复这个错误,我有一些想法,但我想知道在单元测试和"Laravel方法"方面,这里的最佳实践是什么。
按照我的想法,我有一个EntryStatus表,它有静态状态"pending"=>0、"awaiting_payment"=>1、"payed"=>2等。我在我的App\Entry模型>App\EntryStatos中创建了一个关系。想法如下:
原计划;对于单元测试,我需要每次为每个测试播种静态EntryStatus表。查看文档,我会使用类似setUp((>$this->artisan('db:seed'(的东西。但这感觉真的会减慢测试速度。除非有一种方法可以在所有测试开始之前对DB进行一次种子设定。
尝试创建一个创建静态数据的工厂("支付"=>0,"awaiting_payment"=>1(,但我每次都需要手动更新数据库种子和工厂以匹配,这似乎很笨拙。
在Laravel文档测试文档中,他们有这个例子$factory->state(App\User::class,'delaud',['account_status'=>'delaul',](。这让我觉得我可以完全删除关系表EntryStatus,并在Entry中使用一个字符串列来表示状态。我认为这将是最好的解决方案,但我担心我们使用id作为状态是有原因的,因为我认为它们在搜索查询中更快。但如果没有,我的雕像将被修复,这似乎是最有说服力的解决方案。
另一种选择是将雕像存储为整数,记下什么状态是什么整数,但这似乎不正确。
记录尚未创建,在工厂中以这种方式分配静态关系不是一个好主意。
您可以使用工厂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,
]);
});