2017-10-13 5 views
1

たとえば、生データを取り込んで解析し、レポートの数値を返すクラスがあります。ステップバイステップのいくつかのレポートの生データのproccessing、のは、だから、クラスが本当に一つだけを行いSomeReportDataProvider高凝集性ではあるが複雑な論理を持つテストクラス

class SomeReportDataProvider 
{ 
    public function report(array $data) 
    { 
     $data = $this->prepare($data); 

     $report = []; 
     foreach ($data as $item) { 
      if ($row->somefield == 'somevalue') { 
       $report = $this->doThis($report, $row); 
      } else { 
       $report = $this->doThat($report, $row); 
      } 
     } 

     // ... do something else 

     $report = $this->postProcess($report); 

     return $report; 
    } 

    protected function doThis($item) 
    { 
     // ... do some math, probably call some other methods 
    } 

    protected function doThat($item) 
    { 
     // ... do other math 
    } 

    // ... and so on 
} 

それを呼ぶことにしましょう。これは、5-10行の大きな4-6の方法ではありません。その方法はすべて密接に関連しており、一つの目的を果たしているので、結束力が高いと言えます。しかし、クラスをテストする最良の方法は何ですか?

私が「実装ではないテストの振舞い」という考え方でアプローチしようとすると、私はそれを1つのパブリックメソッドしかテストしないといけません。このアプローチの利点は、後でテストに触れることなく後でクラスをリファクタリングするのが簡単であることと、それがまったく同じ動作をしていることを確信していることです。しかし、単一のメソッド、多すぎる可能性のあるコードパスを通してすべてのケースをカバーするのは本当に難しいかもしれません。

ほとんどの(おそらくすべての)メソッドを公開し、それらを孤立してテストすることができますが、クラスとアルゴリズムのカプセル化を破って実装の詳細をテストしています。どんなリファクタリングも、より困難になり、望ましくない行動の変化が起こりやすくなります。

最後に、小さなクラスに分割することができます。ほとんどの場合、1つまたは2つのメソッドがあります。しかし、凝縮性の高いクラスをより小さくて緊密に結合したクラスに分けることは、本当に良い考えですか?それは非常に特殊なことですが、他の場所では再利用されません。また、それはまだリファクタリングするのが難しいでしょう。また、他の開発者がどのように動作するかを素早く把握するのは難しいでしょう。

答えて

1

私の経験上、テストを簡略化する最良の方法であるため、最後のオプションで言うように、できるだけクラスを分割することを常に試みています。これは非常に有効な理由です...
また、私はあなたに同意しません - 私はこのアプローチにより、将来的にリファクタリングが容易になり、すべてをまとめた大きなクラスではなく、より理解しやすくなると思います...

あなたのコードを見ると、私は、別々の "役割"の束を見ることができます: ReportDataPreparatorThisDoerThatDoerReportPostProcessor(明らかにあなたはより良い名前を見つけることができます:)

将来的にそれらの一部を再利用したいかもしれませんが、そうでない場合でもレポートに固有のものであっても、それらを別の名前空間とフォルダに入れることができます( "レポートモジュール" )。
このレポートモジュールには、ReporterInterfaceという1つのユニークなAPIがあり、レポータがプライベートメソッド、他のクラス、またはバックグラウンドでシステム全体を使用しているかどうかにかかわらず、彼らは単にシステムの残りの部分の観点から、そう$reporter->report($data) ...

を呼び出す必要があり、何もあなたのレポートサービスは、すべて一緒に残っている、変化していない、とあなたのユニットテストは書き、維持するために非常に簡単です...

+0

あまりにも多くの依存関係を持つクラスを取得できませんか?また、私たちはテストでそれらのすべてを嘲笑/スタブする必要がありますか?私たちがやるならば、私たちはたくさんのモックで終わります。それを手配するのに多くの時間がかかり、多くの人によると最良のテスト方法ではありません。私たちが嘲笑しなければ、多くのコードパスの問題はまだ残っています... – Dmitri

+0

私はそれが少し味の問題だと思っていますが、状況に大きく依存しています - 個人的にはあまりにも多くの機能1つのクラス(いずれにしても、すべてのデープがレポータークラスに入るわけではなく、他のデープで構成されていても構いません)。モックに関しては、私のアプローチは通常、テストですべてを嘲笑していますが、テストされているクラスです...これはimhoがテストするものです。これは、モジュール全体の実際の動作をテストする場合は、一緒に働くと、別々の統合テストを追加することができますが、単体テストについては、少なくとも私がやることです – MikO

関連する問題