2017-11-20 1 views
2

テスト可能なコードのテストと作成を初めて行ったので、この単純なシナリオを処理する正しい方法を明確にしています。私は他の質問や答えを同じようなタイトルで読んだことがありますが、私が求めていることに対して明確な答えを提示していないようです。Laravelの別のモデルでメソッドを呼び出すユニットテストモデルメソッドの使用方法

私は私のPickingクラスのインスタンスでshipped()メソッドを呼び出して、コントローラを持っている:

class MyController extends \BaseController { 

    public function controllerMethod() { 
     $picking = new Picking; 
     $picking->shipped($shipmentData); 
    } 
} 

Pickingモデルは次のようになります。

class Picking extends \Eloquent { 

    public function order() { 
     return $this->belongsTo('Order'); 
    }  

    public function shipped($shipmentData) { 
     $this->carrier = $shipmentData['Carrier']; 
     $this->service = $shipmentData['Service']; 
     $this->is_shipped = true; 
     $this->save(); 

     $this->order->pickingShipped(); 
    } 
} 

あなたが見ることができるように、このshipped()方法いくつかのデータを保存した後、OrderpickingShipped()メソッドを呼び出します。

今、私はshipped()メソッドのテストを書こうとしていますが、これを行う適切な方法がわかりません。私は嘲笑について読んだことがあるが、これが嘲笑が必要な状況であれば混乱している。私はいくつかの解決策を考えてきましたが、いずれかが正しいかどうかはわかりません。

1)コントローラーがpickingShipped()メソッドを呼び出すようにコードを並べ替え、shipped()メソッドから削除できるようにしてテストを簡素化します。

例えば、shipped()方法の最後の行が除去されると、制御コードが変更になる:試験において

$picking = new Picking; 
$picking->shipped($shipmentData); 
$picking->order->pickingShipped(); 

2)は、そのようorderにモックメソッドを使用テストでは、pickingShipped()メソッドが呼び出されたことを単純に確認できます。

何が説明されているのかに沿って何かhereこれは、テストはこのような何かを行うことができますを意味します:

$order->expects($this->once())->method('pickingShipped') 

しかし、私はそれは私も順序依存性ではなく、このようなshipped()メソッド内order関係、に頼るを注入する必要があることを意味すると思う:

class Picking extends \Eloquent { 

    public function order() { 
     return $this->belongsTo('Order'); 
    }  

    public function shipped(Order $order, $shipmentData) { 
     $this->carrier = $shipmentData['Carrier']; 
     $this->service = $shipmentData['Service']; 
     $this->is_shipped = true; 
     $this->save(); 

     $order->pickingShipped(); 
    } 
} 

そして、コントローラのコードは次のようになりなければならないでしょう:

$picking = new Picking; 
$picking->shipped($picking->order, $shipmentData); 

これは少しstranを感じています私は本当に何が正しいのかよく分かりません。

私の質問は、このコードを書いてテストする正しい方法は何ですか? shipped()メソッドが適切なデータを自身で設定するのは簡単ですが、最後にpickingShipped()を呼び出すのはどうでしょうか?これは、テストをより複雑にするようです。だからコードを再配置する必要がありますか?もしそうなら、どうですか?または、これは私が2番目のオプションで概説したような嘲笑のための共通のユースケースですか?もしそうなら、私が示しているように依存関係を注入するのは正しいですか?

答えて

0

私はPHP開発者ではありません。そのため、言語機能がブロッカーになる可能性があります。

依存性注入メソッドは、依存関係を呼び出して、後で永続性と動作を分離できるため、より良い方法であることをお勧めします。例えば、PickingまたはPickerはより良い動作名ですが、PickingRecordはデータに適しているかもしれません。あなたは、私はあなたが最後に使用した方法(インジェクション)を好きなPHPのデフォルト引数を設定することができますし、現在これは、あなたがorderを無視できるようになる

public function shipped($shipmentData, Order $order = $this->order) { 
    $this->carrier = $shipmentData['Carrier']; 
    $this->service = $shipmentData['Service']; 
    $this->is_shipped = true; 
    $this->save(); 

    $order->pickingShipped(); 
} 

のようなものを簡素化することができれば、いずれの場合においても

プロダクトコードの依存関係をテストし、 orderというオブジェクトをダブルまたは他のタイプのオブジェクトに挿入し、そのメソッドが orderオブジェクトで呼び出されたことを単純にアサートします。統合テストでは、単体テストに倍精度を挿入していても、インターフェイスが引き続きメッシュを合わせているかどうかを監視し続ける必要があります。

これは私がRubyでこれを行う方法です。

+0

フィードバックありがとうございます!このアプローチの私の唯一の問題は、実際には許されるべきでないときにメソッドに '$ order 'を渡すことができるということです。このメソッドのポイントは、ピッキングの順番ではなく、ピッキングの順番で 'pickingShipped'を呼び出さなければならないということです。つまり、テスト目的でのみこのパラメータを追加しています。テスト目的のためだけにメソッドシグネチャを変更するのは奇妙なことです。今や、この方法は、実際には使用すべきではない動作に使用されるべきであることを示唆しています。 – flyingL123

+0

デフォルトの引数に関しては、yesのPHPはそれらを渡すことができますが、 '$ this-> order'のような動的な値を持つことはできません。この場合、デフォルト値を 'null'に設定し、メソッドの最初に' if(is_null($ order))$ order = $ this-> order; 'を実行すると、しかし、私が上で述べたように、この依存性注入のアプローチは、私にとって正しいと感じていません。 – flyingL123

0

私は気分が良い解決策を考え出しました。今私はそれを見ることはかなり明白に思われる。私がしたのは、試験のために模擬注文を返すように、$picking->orderプロパティを設定しただけです。 shipped()方法は$this->orderを呼び出したときに

$order = Mockery::mock(Order::class); 

$picking = new Picking; 
$picking->order = $order; 

$order->shouldReceive('pickingShipped') 
    ->with($picking) 
    ->once(); 

$picking->shipped($shipmentData); 

は今、それは私が定義されて嘲笑$orderオブジェクトを取得し、テストが正常に動作します。

これは適切な解決策のようです。

関連する問題