必须让被测代码通过容器解析依赖而非手动new实例;正确做法是构造函数注入,测试前用bind()/singleton()/instance()替换绑定,singleton类需teardown清理。

在 Laravel 6 的测试中替换容器绑定,核心前提是:**必须让被测代码通过容器解析依赖,而不是手动 new 实例**。只有这样,你才能用 mock 或重新绑定覆盖原有行为。
确保依赖由容器注入而非手动创建
如果控制器或服务里写了 new Service(),测试时无论你怎么 bind 或 mock,都完全无效——容器根本没参与对象创建过程。
✅ 正确做法是使用构造函数注入:
- 在控制器中声明类型提示:
public function __construct(Service $service) - Laravel 会自动从容器解析该实例,前提是
Service已正确绑定(默认类可直接解析) - 避免在方法内、或构造函数里用
new创建关键依赖
在测试中用 bind() 或 singleton() 替换绑定
测试前调用 $this->app->bind() 或 $this->app->singleton(),就能覆盖原始绑定。注意必须在发起 HTTP 请求或调用被测逻辑之前完成。
- 对无状态类(如 DTO、工具类),用
bind()更安全 - 对有状态或资源类(如缓存、HTTP 客户端),若原绑定是
singleton(),测试中也建议用singleton()替换,否则可能因复用问题导致断言失败 - 示例:
$this->app->bind(ExternalApiService::class, MockExternalApi::class);
使用 partialMock() 或 mock() 拦截具体方法返回值
当需要控制某个方法的返回结果(比如 getNumber()),推荐用 mock()(不是 partialMock())配合容器绑定:
- 先创建 mock 实例:
$mock = $this->mock(Service::class); - 设定期望:
$mock->shouldReceive('getNumber')->andReturn(42); - 再绑定进容器:
$this->app->instance(Service::class, $mock); -
instance()直接注入已初始化对象,适合精准控制行为
清理单例避免测试污染
如果被替换的类原本是 singleton() 绑定,且你在测试中修改了它的内部状态(比如调用了 setter),务必在 tearDown() 中清除:
$this->app->forgetInstance(Service::class);- 否则后续测试可能读到上一个测试遗留的状态,导致随机失败
- 这个步骤对
bind()类无需执行,因为每次解析都是新实例











