模拟地理编码器 Laravel

Mocking GeocoderLaravel

我正在使用 GeocoderLaravel 通过 Laravel 应用程序中的 Google 地图 API 查找位置。我希望能够模拟外观,以便在测试中它实际上不会查询 Google 映射 API,因此我将其注入控制器,但这样做会破坏控制器。这是控制器的相关部分:

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Location;
use Geocoder;

class LocationController extends Controller
{
    protected $geocoder;

    public function __construct(Geocoder $geocoder)
    { 
        $this->geocoder = $geocoder;
    } 

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    { 
        // Get location
        $location = $request->input('location');

        try { 
            // Look up location
            $result = $this->geocoder->geocode($location);

            // Return response
            return response()->json($result->toArray(), 200);
        } catch (\Exception $e) { 
            $data = [ 
                'message' => $e->getMessage()
            ];
            return response()->json($data, 400);
        }
    }
}

当我 运行 测试或尝试向此方法发出请求时出现以下错误:

PHP Fatal error:  Call to undefined method Toin0u\Geocoder\Facade\Geocoder::geocode()

使用 PsySh 在调用之前插入一个断点,看起来确实定义了 geocode() 方法,但我不确定为什么。谁能解释我哪里出错了?

你不能像那样注入外观。 facade 没有 geocode 方法。

Facades 的特殊之处在于它们只提供对 Laravel IoC 的访问,并且不像正常的 classes 那样表现。它们与依赖注入正交。

如果服务提供商创建了别名,您可以注入真实的 Geocoder\Geocoder class,但 doesn't appear 以这种方式设置。

我认为您像往常一样坚持使用外观,例如 Geocoder::geocode(...)

但是...查看 Laravel 如何在测试期间模拟外观:

https://laravel.com/docs/5.1/testing#mocking-facades

这将允许您测试您的控制器,模拟外观调用,这样它就不会真正命中 Google。

更新:

我已经创建了一个拉取请求来使这个 DI 友好:

https://github.com/geocoder-php/GeocoderLaravel/pull/41

如果该请求被合并,您将能够在您的控制器方法中注入 \Geocoder\Geocoder,我自己非常喜欢!