Laravel测试中使用Factory关联创建Group出现重复记录的解决方法
问题:Laravel工厂使用hasMeetings时生成重复Group记录
Laravel 8.12应用,使用Pest PHP进行测试。groups与meetings表为一对多关系:一个Group拥有多个Meeting,一个Meeting属于一个Group。
单独创建Group时测试正常,Groups表仅存在1条记录;但通过关联关系创建包含Meeting的Group时,Groups表生成了2条记录,不符合预期。
仅创建Group的测试用例
test('user see all meetings and registered groups successful', function () { Group::factory()->create(); dd(Group::pluck('id')); actingWithPermission($this->user, $this->permission) ->get($this->route) ->assertViewHasAll([ 'totalRegistered' => 1, 'totalMeetings' => 1, ]); });
此时Groups表仅存在1条记录:
^ Illuminate\Support\Collection^ {#3995 #items: array:1 [ 0 => 36 ] #escapeWhenCastingToString: false }
关联创建Meeting的Group测试用例
test('user see all meetings and registered groups successful', function () { Group::factory() ->hasMeetings(1) ->create(); dd(Group::pluck('id')); actingWithPermission($this->user, $this->permission) ->get($this->route) ->assertViewHasAll([ 'totalRegistered' => 1, 'totalMeetings' => 1, ]); });
此时Groups表存在2条记录:
^ Illuminate\Support\Collection^ {#1847 #items: array:2 [ 0 => 36 1 => 37 ] #escapeWhenCastingToString: false }
Group模型中的关系定义
public function meetings() { return $this->hasMany(Meeting::class); }
修复方案
问题根源在于Meeting工厂的定义中自动创建了关联的Group,导致调用hasMeetings(1)时出现重复创建:
- 首先
Group::factory()->hasMeetings(1)->create()会创建一个Group; - 随后Meeting工厂在生成Meeting时,又自动创建了另一个Group来关联,最终产生两条Group记录。
具体修复步骤:
- 检查Meeting工厂的代码,若存在类似以下自动创建Group的逻辑,需要移除或调整:
// 错误示例:Meeting工厂自动创建Group class MeetingFactory extends Factory { public function definition() { return [ 'group_id' => Group::factory(), // 这里会自动创建新Group // 其他字段 ]; } }
- 修改Meeting工厂,让它依赖外部传入的
group_id,而非自动创建:
class MeetingFactory extends Factory { public function definition() { return [ // 只定义其他字段,不自动生成group_id 'title' => $this->faker->sentence(), // ...其他字段 ]; } // 可选:添加一个状态方法,用于关联指定Group public function forGroup(Group $group) { return $this->state(fn (array $attributes) => [ 'group_id' => $group->id, ]); } }
修改后,Group::factory()->hasMeetings(1)->create()会自动将生成的Meeting关联到当前创建的Group,不会额外创建新的Group,Groups表只会有1条记录。
或者,也可以在调用hasMeetings时显式指定关联的Group,避免重复创建:
Group::factory() ->hasMeetings(1, function (array $attributes, Group $group) { return ['group_id' => $group->id]; }) ->create();
内容的提问来源于stack exchange,提问作者Theodory
相关产品推荐
相关产品推荐

