2017-10-13 61 views
1

例如,我有一个采用原始数据,分析数据并返回报告数字的类。让我们把它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行。它的所有方法都是紧密相关的,并且有一个目的,所以我认为它具有很高的凝聚力。但是什么是测试班级的最佳方式?

如果我尝试的心态“测试行为,不执行”办法吧,我应该测试仅是单一的公共方法。这种方法的优点在于,即使未触及测试,也可以很容易地重构类,并且我确信它仍然具有完全相同的行为。但是通过单一方法覆盖所有情况也可能非常困难,可能的代码路径太多。

我可以让大部分(可能全部)的方法public和隔离测试他们,但后来我打破阶级和算法的封装和测试它的实现细节。任何重构都将变得更加困难和不必要的行为变化。

作为最后一种选择,我可以将它分成小类,最有可能有1或2种方法。但是将高度凝聚力的课堂分成更小,紧密耦合的课程,是否真的是一个好主意,这些课程做的非常具体,并且不会在其他地方重复使用?而且重构仍然会更困难。对于其他开发人员来说,可能很难快速了解它的工作原理。

回答

1

我总是试图去为分手了班尽可能,就像你在你的最后一个选项说,因为在我的经验,这是简化测试的最好方式,这本身就是一个非常有效的理由...
另外,我不同意你的看法 - 我觉得这个方法可以更容易地在未来的重构,并更容易理解,而不是一个大的类都在一起......

你的代码来看,我可以看到一堆单独的“角色”:ReporterInterface,Reporter,ReportDataPreparator,ThisDoer,ThatDoer,ReportPostProcessor(显然你可以找到更好的名字:)

你可能想要重用他们中的一些在未来,但即使不是这样,所有这些都是非常具体的报告,你可以把它们放在一个单独的命名空间和文件夹(如“报告模块” )。
该报告模块都有一个独特的API,这是你的ReporterInterface,和系统的所有其他部分只需要关心这个接口,不论是记者是否使用私有方法,其他类,或者在后台一个完整的系统 - 他们只需要调用$reporter->report($data) ...

因此,从系统的其余部分的角度来看,没有什么变化,您的报告服务仍然都在一起,和你的单元测试是更容易编写和维护...

+0

那我们不会得到一个有太多依赖的类吗?另外,我们是否应该模拟/存留所有测试?如果我们这样做,我们会得到很多嘲笑,安排它们需要很多时间,而且很多人都不是最好的测试方式。如果我们不嘲笑,那么仍然存在许多代码路径的问题... – Dmitri

+0

我想这是一个味道问题,很大程度上取决于情况 - 个人而言,我更喜欢太多的代码而不是太多的功能一个班级(无论如何,你可以用一种并不是所有的记录都进入记者班但是在其他记录里)的方式来组织结构。至于模拟,我的方法通常是在测试中嘲笑_everything_,但正在测试的类......这是唯一的正确_unit_测试事情的方法......如果你想测试整个“模块”的真实行为,一起工作,您可以添加单独的集成测试,但对于单元集成测试,这是我至少做的 – MikO