Laravel Incident控制器Feature测试报错,寻求CRUD测试解决方案
Laravel Incident控制器Feature测试问题解决
问题概述
作为Laravel单元测试与Feature测试新手,为Incident控制器编写CRUD操作的Feature测试时,遇到多个报错导致测试无法正常通过。
报错明细
1. Store测试失败
数据库中生成的记录与测试提交的数据不匹配:
Failed asserting that a row in the table [incidents] matches the attributes { "name": "Test Incident", "description": "This is a test incident", "assigned_to": "User", "completed_status": "open" }. Found: [ { "id": 29, "name": "INC1111111", "description": "PHPUnit Test", "assigned_to": "Admin", "completed_status": "open", "created_at": "2023-06-06 10:57:55", "updated_at": "2023-06-06 10:57:55" } ].
2. Update/Destroy测试报错
Call to undefined method App\Models\Incident::factory()
解决步骤
1. 修复Factory未定义问题
Laravel模型使用工厂类需要满足两个条件:模型引入HasFactory trait,同时存在对应工厂类。
步骤1:给Incident模型添加HasFactory trait
修改app/Models/Incident.php:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class Incident extends Model { use HasFactory; // 添加该trait // 配置允许批量赋值的字段 protected $fillable = [ 'name', 'description', 'assigned_to', 'completed_status' ]; }
步骤2:生成Incident工厂类
在终端执行Artisan命令:
php artisan make:factory IncidentFactory --model=Incident
打开生成的database/factories/IncidentFactory.php,定义默认字段值:
<?php namespace Database\Factories; use Illuminate\Database\Eloquent\Factories\Factory; use App\Models\Incident; class IncidentFactory extends Factory { protected $model = Incident::class; public function definition() { return [ 'name' => $this->faker->unique()->regexify('INC[0-9]{7}'), 'description' => $this->faker->sentence(), 'assigned_to' => $this->faker->name(), 'completed_status' => $this->faker->randomElement(['open', 'closed', 'in_progress']) ]; } }
2. 启用数据库刷新,避免测试数据残留
在IncidentTest中启用RefreshDatabase trait,确保每次测试都在干净的数据库环境中运行:
class IncidentTest extends TestCase { use RefreshDatabase; // 取消注释该行 // ... 其他测试方法 }
3. 修复Store测试数据残留问题
启用RefreshDatabase后,Store测试会在全新的数据库中执行,提交的数据会正确写入,不会被旧测试数据干扰。
4. 修复Update测试的路由与验证字段错误
问题点:
- 使用了编辑页面的GET路由
incidents.edit,更新操作应使用PUT/PATCH路由incidents.update - 控制器update方法的验证规则字段为
completed,但测试提交的是completed_status,导致验证失败 - 重定向路由写成单数
incident.index,正确路由应为复数incidents.index
修改后的update测试方法:
public function testUpdate() { $incident = Incident::factory()->create(); // 发送PUT请求到正确的更新路由 $response = $this->put(route('incidents.update', $incident), [ 'name' => 'Updated Incident', 'description' => 'This is an updated incident', 'assigned_to' => 'Admin', 'completed_status' => 'open', ]); $this->assertDatabaseHas('incidents', [ 'id' => $incident->id, 'name' => 'Updated Incident', 'description' => 'This is an updated incident', 'assigned_to' => 'Admin', 'completed_status' => 'open', ]); $response->assertRedirect(route('incidents.index')); }
同时修改IncidentController的update方法,统一验证字段名:
public function update(Request $request, Incident $incident) { $request->validate([ 'name' => 'required', 'description' => 'required', 'assigned_to' => 'required', 'completed_status' => 'required', // 改为与store方法一致的字段名 ]); $incident->update($request->all()); return redirect()->route('incidents.index') ->with('success','Incident updated successfully'); }
5. 修复Destroy测试的重定向路由错误
将重定向路由从单数incident.index改为复数incidents.index:
public function testDestroy() { $incident = Incident::factory()->create(); $response = $this->delete(route('incidents.destroy', $incident->id)); $this->assertDatabaseMissing('incidents', [ 'id' => $incident->id, ]); $response->assertRedirect(route('incidents.index')); }
验证测试运行
完成所有修改后,执行测试命令:
php artisan test --filter IncidentTest
所有CRUD测试即可正常通过。
内容的提问来源于stack exchange,提问作者Ashleigh Halliday
相关产品推荐
相关产品推荐

