0

Lumen v5.0.10 で問題が発生しました。主に TDD とバンドルされたphpunit拡張機能を使用してアプリケーションを設計しています。私は基本的にBindingResolutionException「App\Contracts\SubscriberInteractionInterface」を取得しています。これは、次のように登録されているApp\Servicesに実装されているディレクトリApp\Contractsのインターフェイスです。AppServiceProvider

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {

        // Owner manager
        $this->app->singleton(
            'App\Contracts\OwnerInteractionInterface',
            'App\Services\OwnerManager'
        );

        // Subscriber manager
        $this->app->singleton(
            'App\Contracts\SubscriberInteractionInterface', 
            'App\Services\SubscriberManager'
        );

//      dd($this->app->bound('App\Contracts\SubscriberInteractionInterface'));
    }
}

私の欲求不満は、関数の最後の行のコメントを外すと、App\Contracts\SubscriberInteractionInterfaceバインドされていることを示していることです (したがって、解決される可能性があります)。

次に、効果的にこのように見えるコントローラーがあります

class MyController extends Controller {

    public function __construct(LoggerInterface $log)
    {
        $this->log = $log;
    } 


    public function index(Request $request)
    {
           if (/* Seems to come from owner */)
           {
               $owners = App::make('App\Contracts\OwnerInteractionInterface');
               return $owners->process($request);
           }

           if (/* Seems to come from subscriber */)
           {
               $subscribers = App::make('App\Contracts\SubscriberInteractionInterface');
               return $subscribers->process($request);
           }
    }
}

このように使用するのは、関連するものだけをインスタンス化する必要があり (型ヒントを付けた場合のように両方ではなく)、それぞれのコンストラクターに型ヒント付きの依存関係があるためです。

問題は、必要なテストのルートは正常にOwnerInteractionInterface実行されますが、必要なテストのルートは実行さSubscriberInteractionInterfaceれないことです。実装とインターフェイスは大部分が似ており、前に示したように、両方が同時に登録され、SubscriberInteractionInterfaceバインドされていることを確認できます。実際、次の行を入れると:

dd(App::bound('App\Contracts\SubscriberInteractionInterface'));

一番上にtrueindex()を返します。テストはたまたま、を使用するパスが最初に実行され、それが正常に解決され、次に他のテストが. ただし、他のテストを省略してそのテストだけを実行すると、すべてがスムーズに進みます。テストは異なるファイルにあり、私が行う唯一のセットアップは、示されているものとはまったく異なるバインディングの代わりにサードパーティ API のモックをバインドすることであり、そのコードはこれらのクラスに触れていません。これは関数内で行われ、その中で呼び出すようにしています。OwnerInteractionInterfaceBindingResolutionExceptionsetUp()parent::setUp()

何が起きてる?1 つの具象インスタンスをバインドすると、非具象バインディングが から消去されるのIoCでしょうか? それとも、デフォルトの設定では、あるテストから別のテストに何らかの影響が移ることが許されているのでしょうか?

回避策があることはわかっていますが、完全なテストスイートを実行しないという制約は面倒です。インターフェイスからインスタンスを解決するのではなく、インスタンスを直接使用するだけで、テストが簡単になるように見え始めています。

IoCまた、解決可能なバインディングを検査する方法を知っている人はいますか?

4

2 に答える 2

1

さらにデバッグを試みたapp(...)ところ、代わりにを使用するとApp::make(...)問題が発生しないことがわかりました。クラスのeval(\Psy\sh())呼び出しを行いtearDownTestCaseいくつかのテストの後、次の結果が得られることがわかりました。

>>> app()->bound('App\Contracts\OwnerInteractionInterface')
=> true
>>> App::bound('App\Contracts\OwnerInteractionInterface')
=> false
>>> App::getFacadeRoot() == app()           
=> false 

これはどういうわけか、ファサードがオブジェクトを解決するために使用するインスタンスが、メソッドによって作成された現在のインスタンスと同じではLaravel\Lumen\Applicationないということですこのインスタンスは、メソッド内の呼び出しによってすべてのバインディングがクリアされた古いインスタンスであり、最初の呼び出しに続くテストでカスタム バインディングを解決できないと思います。AppsetUp()$this->app->flush()tearDown()tearDown()

問題を突き止めようとしましたが、今のところ、この回避策でこのプロジェクトを終了する必要があります。実際の原因が見つかった場合は、この回答を更新します。

于 2015-06-23T13:48:54.347 に答える
0

use の代わりに、 methodbindを使用できますbindIf。コンテナは、アブストラクトがバインドされているかどうかをチェックします。そうでない場合は、アブストラクトをバインドし、その逆も同様です。ここで API を読むことができます。

したがって、を使用するsingleton場合は、bindIflike を使用できます。

// Owner manager
$this->app->bindIf(
    'App\Contracts\OwnerInteractionInterface',
    'App\Services\OwnerManager',
    true
);

// Subscriber manager
$this->app->bindIf(
    'App\Contracts\SubscriberInteractionInterface', 
    'App\Services\SubscriberManager',
    true
);
于 2015-06-22T07:35:15.370 に答える