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逻辑
测试里的几个问题需要修正:
- 不需要手动mock
UserIndexGetRequest的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
相关产品推荐
相关产品推荐

