You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 05:45:09