例如,我有一个类,它接收原始数据,分析它并返回报告的数字。我们称之为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
}
因此,该课程实际上只做了一件事,一步一步地处理某些报告的原始数据。它不大,最有可能4-6种方法,5-10行。它的所有方法都是紧密相关的,并且有一个目的,所以我会说它具有很高的凝聚力。但是测试课程的最佳方法是什么?
如果我尝试用心态“测试行为,而不是实现”来接近它,我应该只测试它的单一公共方法。这种方法的优点是,以后很容易重构该类,甚至没有触及测试,我相信它仍然会表现出完全相同的行为。但是通过单一方法,太多可能的代码路径来覆盖所有情况也很难。
我可以将大多数(可能是全部)方法公开并单独测试它们,但随后我打破了类和算法的封装并测试了它的实现细节。任何重构都会更加困难,并且更有可能发生不必要的行为变化。
作为最后一个选项,我可以把它分成小类,最有可能有1或2种方法。但是,将高度紧密的类分解为更小,紧密耦合的类,这是非常好的主意,它们做了非常具体的事情并且不会在其他地方重复使用吗?重构它仍然会更加困难。并且其他开发人员可能更难以快速全面了解其工作原理。
答案 0 :(得分:1)
我总是试着尽可能多地拆分课程,就像你在上一个选项中所说的那样,因为根据我的经验,这是简化测试的最佳方法,这本身就是一个非常正确的理由... <登记/> 另外,我不同意你的意见 - 我认为这种方法可以让你在将来更容易重构,更容易理解,而不是一个包含所有内容的大班......
查看您的代码,我可以看到一堆独立的“角色”:ReporterInterface
,Reporter
,ReportDataPreparator
,ThisDoer
,ThatDoer
,{ {1}}(显然你可以找到更好的名字:)。
您可能希望将来重用其中一些,但即使不是这种情况,并且所有这些都非常特定于报告,您只需将它们放在单独的命名空间和文件夹中(如“报告模块“)。
此报告模块有一个唯一的API,即ReportPostProcessor
,系统的其余部分只需要关心该接口,无论该报告者是否使用私有方法,其他类或整个系统。背景 - 他们只需要致电ReporterInterface
...
因此,从系统其他部分的角度来看,没有任何变化,您的报告服务仍然在一起,您的单元测试很多更容易编写和维护......