たとえば、生データを取り込んで解析し、レポートの数値を返すクラスがあります。ステップバイステップのいくつかのレポートの生データの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つのメソッドがあります。しかし、凝縮性の高いクラスをより小さくて緊密に結合したクラスに分けることは、本当に良い考えですか?それは非常に特殊なことですが、他の場所では再利用されません。また、それはまだリファクタリングするのが難しいでしょう。また、他の開発者がどのように動作するかを素早く把握するのは難しいでしょう。
あまりにも多くの依存関係を持つクラスを取得できませんか?また、私たちはテストでそれらのすべてを嘲笑/スタブする必要がありますか?私たちがやるならば、私たちはたくさんのモックで終わります。それを手配するのに多くの時間がかかり、多くの人によると最良のテスト方法ではありません。私たちが嘲笑しなければ、多くのコードパスの問題はまだ残っています... – Dmitri
私はそれが少し味の問題だと思っていますが、状況に大きく依存しています - 個人的にはあまりにも多くの機能1つのクラス(いずれにしても、すべてのデープがレポータークラスに入るわけではなく、他のデープで構成されていても構いません)。モックに関しては、私のアプローチは通常、テストですべてを嘲笑していますが、テストされているクラスです...これはimhoがテストするものです。これは、モジュール全体の実際の動作をテストする場合は、一緒に働くと、別々の統合テストを追加することができますが、単体テストについては、少なくとも私がやることです – MikO