通过模拟依赖来测试Laravel自定义包

时间:2017-10-09 13:47:23

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

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

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是否以预期的方式运行(并将数据存储在数据库中)。

如何指示Service Container仅在测试期间注入Mocked对象?或者我是以完全错误的方式做到这一点?

任何帮助将不胜感激。

提前致谢

1 个答案:

答案 0 :(得分: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了解如何使用模拟构建器和生成的模拟。