Laravel PhpUnit 依赖注入

Posted

技术标签:

【中文标题】Laravel PhpUnit 依赖注入【英文标题】:Laravel PhpUnit Dependency Injection 【发布时间】:2022-01-16 03:40:20 【问题描述】:

我正在使用依赖注入来调用 Laravel 中的自定义服务,它工作正常。但是当我使用接口将这些依赖项注入我的 phpunit 测试用例类时,我收到以下错误:

目标 [App\Services\Interfaces\CarServiceInterface] 不可实例化。

虽然接口已正确绑定到提供程序中的目标具体类。 我使用了不同的样式,例如通过__construct() 方法注入、注入到测试方法甚至调用app() 方法,但它们都不起作用。

测试文件:

private $carService;

public function setUp(): void

    parent::setUp();

    $this->carService = app(CarServiceInterface::class);

提供者:

$this->app->bind(
    App\Services\Interfaces\CarServiceInterface::class,
    App\Services\CarService::class
);

这样做的正确方法是什么?

【问题讨论】:

你在哪里写你的测试?在单元测试还是在功能测试部分? @BABAKASHRAFI 在单元测试中 您需要在功能测试部分编写您的测试,因为它继承自具有CreatesApplication 特征的自定义测试用例。 @BABAKASHRAFI 好吧,我将测试移至功能部分,但我仍然收到错误。 可能是绑定错误。 【参考方案1】:

您需要在特性部分编写测试,因为特性测试是从 laravel 基本测试用例继承的,并且它们具有 CreatesApplication 特征。 Refer to here

之后,您可以在测试中使用app('Your abstract class namespace ') 方法或$this->app->make('Your abstract class namespace ') 简单地获取具体的类实例。

【讨论】:

【参考方案2】:

显然是错误的测试方法。 为什么在测试课上需要 DI?! 在测试类中,您必须准备并可能绑定/模拟所需的类。 然后测试你的代码。

错误的第二部分表明,尽管您的假设,该类没有正确绑定。

顺便说一句,如果你认为我错过了什么,而你需要 DI,请使用 bindsingleton 方法。

$this->app->bind(CarServiceInterface::class, fn () => $exampleInstance);

//or 

$this->app->singleton(CarServiceInterface::class, fn () => $exampleInstance);

现在您可以像这样使用容器访问您的界面而不会出现 DI 错误:

$this->app[CarServiceInterface::class]
//or
$this->app->make(CarServiceInterface::class)
//or
app(CarServiceInterface::class)

【讨论】:

【参考方案3】:

好吧,我终于找到了问题所在。尽管其他人给出的所有答案/建议也是正确的。 我的测试用例类扩展了错误的 TestCase 命名空间。通过将其更改为App\TestCase,它得到了修复。

【讨论】:

以上是关于Laravel PhpUnit 依赖注入的主要内容,如果未能解决你的问题,请参考以下文章

Laravel:命令中的依赖注入

译深入研究 Laravel 的依赖注入容器

Laravel:如何模拟依赖注入类方法

Laravel 单元测试依赖注入

laravel依赖注入浅析

Laravel 依赖注入“不可实例化”