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

Laravel8中PHPUnit测试调用原始User模型而非Mock模型问题求助

问题根源

你的控制器构造函数里直接用new User()实例化模型,没有通过Laravel的依赖注入容器解析对象。这种情况下,就算你在测试里把Mock实例绑定到容器,控制器还是会创建原始的User模型实例,导致Mock不生效。

解决方案

1. 修改控制器,使用依赖注入

把控制器的构造函数改成通过依赖注入获取User模型实例,让Laravel容器负责对象的创建和替换:

class UserController extends BaseController
{
    public $user;

    // 通过构造函数注入User模型
    public function __construct(User $user)
    {
        $this->user = $user;
    }

    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index(UserIndexGetRequest $request)
    {
        try {
            $userList = $this->user->getAllUsers($request);

            //is_dropdown will be passed from client call when you want to load or get all dropdown options without pagination
            if (!empty($request->is_dropdown)) {
                $userList = new UserAllDataCollection($userList);
            } else {
                $userList = new UserCollection($userList);
            }
            
            //return error response if no records founds
            if ($userList->isEmpty()) {
                return $this->sendError(__('users.no_data_found'));
            }

            //user list response
            return $this->sendResponse($userList, __('users.all_users_list'));
        } catch (Exception $e) {
            //return error response on exception
            return $this->sendError($e->getMessage(), $e);
        }
    }
}

2. 调整测试用例,修正Mock逻辑

测试里的几个问题需要修正:

  • 不需要手动mockUserIndexGetRequest的passes方法,Laravel测试会自动处理请求验证;如果要测试验证逻辑,单独写用例即可。
  • Mock的getAllUsers方法返回true会导致后续$userList->isEmpty()报错,因为布尔值没有isEmpty方法,需要返回一个集合实例。
  • 目标状态码302不符合接口返回逻辑,接口正常应该返回200或者自定义业务状态码,这里根据控制器逻辑,返回空数据的话是错误响应,需对应调整断言。

修改后的测试用例:

class RouteValidateTest extends TestCase
{
    use WithoutMiddleware;

    public function test_user_list()
    {
        // 创建User模型的Mock实例,指定getAllUsers的返回值
        $mockUserModel = Mockery::mock(User::class);
        $mockUserModel->shouldReceive('getAllUsers')
            ->once()
            ->with(Mockery::any()) // 若需指定请求参数,可替换为具体请求实例
            ->andReturn(collect()); // 返回空集合,模拟无数据场景

        // 绑定Mock实例到容器
        $this->app->instance(User::class, $mockUserModel);

        // 发起请求
        $response = $this->get('/api/v1/user', ['name' => 'laaa']);

        // 验证响应状态码(根据控制器错误响应的实际状态码调整)
        $response->assertStatus(400);
        // 验证响应内容包含指定错误信息
        $response->assertJson([
            'message' => __('users.no_data_found')
        ]);
    }
}
补充说明
  • 依赖注入是Laravel的核心特性之一,不仅能让代码更易测试,还能提高代码的可维护性。
  • 如果必须保留构造函数里的实例化逻辑(不推荐),可以通过容器的make方法获取实例:$this->user = app(User::class);,这样也能让Mock生效,但还是建议用构造注入。

内容的提问来源于stack exchange,提问作者Laxman Sahu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 21:50:27