2015-06-21 39 views
0

我遇到了Lumen v5.0.10的問題,有我在我的智慧結束。我正在設計一個應用程序,主要使用TDD以及附帶的phpunit擴展。我基本上得到了「App \ Contracts \ SubscriberInteractionInterface」的BindingResolutionException。這是在目錄中的接口應用程序\合同其具有註冊在AppServiceProvider像這樣在軟件\服務實現:Lumen IoC綁定分辨率斑點內phpunit測試

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')); 

index()頂部返回。測試碰巧被命令使得使用OwnerInteractionInterface的路徑首先運行並且它解決得很好,然後另一個測試以BindingResolutionException失敗。但是,如果我省略其他測試並運行該測試,那麼一切都會順利進行。測試是在不同的文件中,我所做的唯一設置是綁定第三方API的模擬代替完全不同於所示的綁定,並且沒有任何代碼涉及這些類。這是在setUp()函數內完成的,我確保在其中調用parent::setUp()

這是怎麼回事?難道是綁定一個具體的實例擦除IoC的非具體綁定?還是默認設置允許一些影響從一個測試轉移到另一個測試?

我知道我有一種解決方法,但從不運行完整的測試套件的約束是討厭的。如果我直接使用實例而不是從其接口解析它,它似乎開始變得更容易。

此外,有沒有人知道一種方法來檢查IoC可解析的綁定?

+0

似乎其他人在Laravel遇到與單元測試相似的問題,只有他們在本[問題](https://github.com/laravel/framework/issues/1181)中討論的雄辯事件中遇到它們。 – jeteon

+0

這個問題似乎與Lumen如何在TestCase的tearDown()和setUp()方法中破壞並重新設置應用程序實例有關。第一次工作正常,但是其他時間都不太對勁。這個問題可以通過'OwnerInteractionInterface'和後續的測試來觀察。目前,解決方法是一次只運行**一次**測試。 – jeteon

回答

0

而不是使用bind,您可以使用bindIf方法。容器將檢查摘要是否被綁定。如果不是,它會綁定你的摘要,反之亦然。你可以閱讀api here

所以如果你使用singleton,你可以使用bindIf之類的。

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

// Subscriber manager 
$this->app->bindIf(
    'App\Contracts\SubscriberInteractionInterface', 
    'App\Services\SubscriberManager', 
    true 
); 
+0

似乎沒有骰子。我認爲這基本上是'singleton()'在幕後做的事情。 – jeteon

0

後,在調試的進一步嘗試,我發現,如果你在的地方App::make(...)使用app(...)那麼問題不上來。我把一個eval(\Psy\sh())呼叫在TestCase類的tearDown,發現了一些測試後,你會得到以下結果:

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

這是說,不知何故,Laravel\Lumen\Application實例的App門面用來解析您的對象是而不是與由setUp()方法創建的當前實例相同。我認爲這個實例是舊的,通過tearDown()方法中的$this->app->flush()調用清除了所有綁定,以便它在第一個tearDown()調用之後的任何測試中都不能解析任何自定義綁定。

我試圖追捕這個問題,但現在我不得不用這個解決方法來結束這個項目。如果我找到真正的原因,我會更新這個答案。