Laravel中如何为Controller-Service-Repository模式方法编写单元测试
测试实现方案
我们基于Laravel框架自带的PHPUnit测试组件结合Mockery实现分层单元测试,遵循单测隔离原则:测试上层逻辑时Mock所有下层依赖,仅测试当前层的逻辑正确性,只有仓库层测试可以和测试数据库交互。
1. 前置准备
- 确保phpunit和mockery已经安装(Laravel框架默认已集成)
- 测试类统一放在
tests/Unit目录下,按分层新建对应子目录:Controllers、Services、Repositories - 配置测试环境数据库为内存SQLite(在phpunit.xml中配置,避免影响业务数据库)
2. 控制器index方法单元测试
测试目标:验证控制器能正确从请求中获取用户ID,调用服务层对应方法并返回结果
<?php namespace Tests\Unit\Controllers\Api\v1; use App\Http\Controllers\Api\v1\ChecklistController; use App\Services\ChecklistsServiceInterface; use Illuminate\Http\Request; use Tests\TestCase; class ChecklistControllerTest extends TestCase { public function test_index_calls_service_with_correct_user_id_and_returns_result() { // 模拟用户ID $testUserId = 123; $mockReturnData = collect([ ['id' => 1, 'name' => '测试清单1'], ['id' => 2, 'name' => '测试清单2'] ]); // Mock服务层依赖 $mockService = \Mockery::mock(ChecklistsServiceInterface::class); $mockService->shouldReceive('getUserChecklists') ->once() ->with($testUserId) ->andReturn($mockReturnData); // 模拟请求对象,设置当前登录用户 $request = Request::create('/api/v1/checklists', 'GET'); $request->setUserResolver(function () use ($testUserId) { return (object)['userId' => $testUserId]; }); // 实例化控制器调用index方法 $controller = new ChecklistController($mockService); $result = $controller->index($request); // 断言返回结果正确 $this->assertEquals($mockReturnData, $result); } }
3. 服务层getUserChecklists方法单元测试
测试目标:验证服务层能正确接收用户ID,调用仓库层对应方法并返回结果
<?php namespace Tests\Unit\Services; use App\Repositories\ChecklistsRepositoryInterface; use App\Services\ChecklistsService; use Tests\TestCase; class ChecklistsServiceTest extends TestCase { public function test_get_user_checklists_calls_repository_with_correct_params() { $testUserId = 456; $mockReturnData = collect([['id' => 3, 'name' => '测试清单3']]); // Mock仓库层依赖 $mockRepository = \Mockery::mock(ChecklistsRepositoryInterface::class); $mockRepository->shouldReceive('getUserChecklists') ->once() ->with($testUserId) ->andReturn($mockReturnData); // 实例化服务调用方法 $service = new ChecklistsService($mockRepository); $result = $service->getUserChecklists($testUserId); // 断言返回结果正确 $this->assertEquals($mockReturnData, $result); } }
4. 仓库层getUserChecklists方法单元测试
测试目标:验证仓库层查询逻辑正确,能返回对应用户的所有Checklist记录
注意:这里需要用到Laravel的
RefreshDatabase特性,每次测试后重置测试数据库,避免测试数据互相影响
<?php namespace Tests\Unit\Repositories; use App\Models\Checklist; use App\Repositories\ChecklistsRepository; use Illuminate\Foundation\Testing\RefreshDatabase; use Tests\TestCase; class ChecklistsRepositoryTest extends TestCase { use RefreshDatabase; public function test_get_user_checklists_returns_matched_records() { $testUserId = 789; $otherUserId = 101112; // 创建测试数据:用户789有2条清单,用户101112有1条清单 $userChecklists = Checklist::factory()->count(2)->create(['userId' => $testUserId]); Checklist::factory()->create(['userId' => $otherUserId]); // 实例化仓库调用方法 $repository = new ChecklistsRepository(); $result = $repository->getUserChecklists($testUserId); // 断言返回2条记录,且都是对应用户的 $this->assertCount(2, $result); $result->each(function ($item) use ($testUserId) { $this->assertEquals($testUserId, $item->userId); }); } }
内容的提问来源于stack exchange,提问作者Hellsontime
相关产品推荐
相关产品推荐

