✅ Step0:前提(準備)
・ 認証は用意済(php artisan make:auth 等)。テストでは actingAs() を使用
・ ルートがある:
DELETE /tasks/{task} → TaskController@destroy(name('tasks.destroy'))
・ DELETE メソッドを送る:
<form action="{{ route('tasks.destroy', ['task' => $task->id]) }}" method="POST">
@csrf
@method('DELETE')
<button type="submit">削除</button>
</form>
・ 他人のタスクは削除不可:本記事では404で隠す設計
✅ Step1:テストファイル作成
php artisan make:test DeleteTaskTest
→ tests/Feature/DeleteTaskTest.php が作成される
✅ Step2:テストコードを書く
テストコード例
DeleteTaskTest.php
<?php
namespace Tests\Feature;
use App\Models\Task;
use App\Models\TaskCategory;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class DeleteTaskTest extends TestCase
{
use RefreshDatabase;
// ----- 自分のタスクを削除できる
public function test_user_can_delete_own_task()
{
// ⓪ 前提:カテゴリ投入
$this->seed();
$category = TaskCategory::first();
// ① ユーザー & タスク作成
$user = User::factory()->create();
$task = Task::factory()->create([
'user_id' => $user->id,
'task_category_id' => $category->id,
]);
// ② 認証
$this->actingAs($user);
// ③ 削除実行
$response = $this->delete(route('tasks.destroy', ['task' => $task->id]));
// ④ レスポンス(今回は削除後にリダイレクトOKか否か)
$response->assertStatus(302);
// ⑤ DBから消えていること(物理削除)
$this->assertDatabaseMissing('tasks', ['id' => $task->id]);
}
// ----- 他人のタスクは削除できない
public function test_user_cannot_delete_others_task()
{
// ⓪ 前提:カテゴリ投入
$this->seed();
$category = TaskCategory::first();
// ① ユーザー &. 別ユーザー & タスク作成
$owner = User::factory()->create();
$other = User::factory()->create();
$task = Task::factory()->create([
'user_id' => $owner->id,
'task_category_id' => $category->id,
]);
// ② 認証
$this->actingAs($other);
// ③ 削除実行
$response = $this->delete(route('tasks.destroy', ['task' => $task->id]));
// ④ 不正アクセスは 404(= assertNotFound)
$response->assertNotFound();
// ⑤ まだDBに残っている
$this->assertDatabaseHas('tasks', ['id' => $task->id]);
}
}
🧪 RefreshDatabase を使っている場合は テストごとにシーディングが必要
各テストメソッドの前後でDBが初期化されるため、カテゴリ等の初期データは毎回消えます。
よって各テストの冒頭で $this->seed() を実行します。
✅ Step3:TaskFactory(テスト用の初期 Task を楽に作る)
✅ Step3-1:Factoryファイル作成
php artisan make:factory TaskFactory --model=Task
→ database/factories/TaskFactory.php が作成される
✅ Step3-2:TaskFactory の中身を編集
TaskFactory.php
<?php
namespace Database\Factories;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Task>
*/
class TaskFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition()
{
return [
'user_id' => User::factory(),
'title' => Str::limit($this->faker->sentence(6), 50, ''),
'task_category_id' => 1,
'description' => $this->faker->text,
'start_at' => now(),
'end_at' => now()->addDay(),
'is_completed' => false,
];
}
}
✅ Step4:🌱 TaskCategorySeeder(ID を固定して挿入する理由も含めて)
TaskCategorySeeder.php
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class TaskCategorySeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$taskCategories = [
[
'id' => 1,
'name' => '重要 & 緊急',
'slug' => 'important-urgent'
],
[
'id' => 2,
'name' => '重要',
'slug' => 'important'
],
[
'id' => 3,
'name' => '緊急',
'slug' => 'urgent'
],
[
'id' => 4,
'name' => 'その他',
'slug' => 'other'
],
];
foreach($taskCategories as $taskCategory) {
DB::table('task_categories')->insert([
'id' => $taskCategory['id'],
'name' => $taskCategory['name'],
'slug' => $taskCategory['slug'],
]);
}
}
}
✅ Step5:テスト実行
php artisan test
→ ✅ 緑(Passed)になれば成功!
✅ テストをスキップしたい場合
・ 認証系テスト(メール通知必要)など、いまは通らなくてもいいテストを除外したい場合などで使える。