【问题标题】:Testing Laravel custom package by mocking dependency通过模拟依赖来测试 Laravel 自定义包
【发布时间】:2018-03-20 18:10:53
【问题描述】:

我还在学习 Laravel 和依赖注入。我理解这个概念,但我不知道如何在这种特定情况下模拟依赖项:

MyController.php

use Illuminate\Routing\Controller;    
use MyPackage\Services\ServiceInterface;

class MyController extends Controller{
    protected $service;

    public function __construct(ServiceInterface $service)
    {
        $this->service = $service;
    }    
}

MyServiceProvider.php

use Illuminate\Support\ServiceProvider;

class MyServiceProvider extends ServiceProvider{

    public function register()
    {
        $this->app->bind('MyPackage\Services\ServiceInterface', function ($app) {
            return new MyPackage\Services\ConcreteService(['key'=>'123'], $app->make('GuzzleHttp\Client'));
        });
    }    
}

所以,如您所见,我有一个需要 ServiceInterface 实例的控制器。该实例正在 ServiceProvider 中解析。 ConcreteService 的构造函数需要客户端向 API 执行 Http 请求。此 Http 正在由 Service 容器解析(它将是 Guzzle 的一个实例)。

现在,我如何在我的测试中模拟这个 Guzzle 实例?

理想的结果是这样做:

MyTest.php

...
$this->post(route('routeToActionInMyController'), $params);

所以,在我的测试中,我只需要点击将使用 MyController.php 的特定方法的路线,但我不需要“真正的”Guzzle 实例。我只需要模拟响应来测试 MyController 是否按预期方式运行(并将内容正确存储在数据库中)。

如何指示服务容器仅在测试期间注入 Mocked 对象?还是我这样做的方式完全错误?

任何帮助将不胜感激。

提前致谢

【问题讨论】:

  • class MyServiceProvider extends Controller 看起来是非常糟糕的做法。控制器和服务提供者负责完全不同的事情
  • 哦,很抱歉,打错字了

标签: php unit-testing laravel-5 laravel-testing


【解决方案1】:

在你的测试课中:

class TestingSomething extends TestCase {
     protected function setUp() {
          parent::setUp();
          $mockServiceInterface = $this->getMockBuilder(ServiceInterface::class)->getMock();
          $this->app->instance(ServiceInterface::class,$mockServiceInterface);
     }

     public function testPostToRoute() {
        $this->post(route('routeToActionInMyController'), $params);
    }
 } 

这应该用那个模拟实例替换服务容器中已经绑定的内容。

请参阅PHPUnit manual on chapter 9. Test doubles,了解您可以使用模拟构建器和生成的模拟做什么。

【讨论】:

  • 感谢您的回复@apokryfos。这意味着我需要更换整个绑定?我的意思是,我不能只替换 Guzzle 绑定?
  • 如果您通过依赖注入实例化 guzzle,那么您可以模拟 guzzle 客户端。这也应该工作
  • 我认为 Guzzle 开箱即用。检查docs.guzzlephp.org/en/stable/testing.html
  • 我认为我做得很好。你能告诉我它是否正确吗?这就是我正在做的事情:ConcreteService 的构造函数接收一个参数,该参数必须是 Guzzle 的实例。在服务提供者中,我通过执行以下操作传递(注入)该参数: $app->make('GuzzleHttp\Client')
  • 是的,你这样做是正确的,所以在你的测试设置中你可以这样做$this->app->bind('GuzzleHttp\Client', function () { /* code from http://docs.guzzlephp.org/en/stable/testing.html here */ })
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-02-19
  • 1970-01-01
  • 2023-03-27
  • 1970-01-01
  • 2016-03-02
  • 2022-01-09
  • 2019-12-25
相关资源
最近更新 更多