最近一个Sprint大部分时间是在修改一些被Ignore掉的UT。这种先有产品代码再补上的UT本身就不是特别的流畅,再加上被Ignore掉了,所以改起来特别头疼。问题最大的还是某个南非的很有想法的哥们写出来的代码。

     首先头疼的问题是,他会在一个类里面写出所有逻辑,然后把一些逻辑抽取出来放到一个庞大的abstract基类中。

     其次,基类不仅庞大,而且逻辑复杂就像一团乱麻,基类里面,有一些几百行的方法,举个例子,其中有个override的方法,有若干复杂的层次结构,譬如query string信息抽取代码,WCF服务的调用代码,UI所需信息的预处理代码等等。这南非哥们也知道这是一团乱麻,所以对基类稍微拾掇了下。拾掇的方式是通过抽取方法,比如,QueryString里面提取个CustomerId的属性,一个私有方法,里面负责WCF服务调用读出相应的数据,传入参数之一就是之前提取的CustomerId,一个私有方法,根据前面两者的结果,传给WCF服务取出一些辅助信息,欧卖糕的!

     再说俺修这个UT的经历,一开始看见子类的时候,非常简洁,似乎没什么难的,于是开始整UT。创建View的mock,创建子类依赖的几个Service的Stub,大功告成。运行下UT,红的,抛出来个诡异的异常。看看代码,子类用到了一个基类的property,该property依赖于某个Service,而该Service还没有被Stub过,故而抛出来个诡异的异常,没别的,先建个Stub再说。很快,新的Stub出来了,跑下UT,依然是杯具,同样的错,只是报错的地方变掉了。发现子类调用的上述基类的方法调用的私有方法里面还有些依赖没有Arrange,Shoot!接着重复上面的工作。再跑一次,还是红的。。。又看,发现上述私有方法又调用了个私有方法里面对Service还有依赖,又仔细看了下,发现一共有n层私有方法调用更深层次的私有方法,私有方法基本上都对Service有依赖,或者是做Validation,或者是取一些帮助信息。。。这UT没法给他补齐了。依赖太多。

      后来花了一整天时间试图想办法把各种依赖都弄掉,最后发现,这个针插不进水泼不进的基类子类结构,彻彻底底把我打败了。好吧,你赢了,南非人。

      由这产生了些心得。

类的设计,尽量小点,职责单一,它才不会有过多的依赖,这样方便代码维护。

弄出来个头重脚轻的类型结构,实在是别扭,即使基类是个抽象类,也可以通过生成它的Stub对它进行UT啊,逻辑稍复杂的基类,依靠子类的逻辑,很难保证基类的覆盖率。

为什么要把类型对外界的依赖隐藏在私有方法里面呢?没必要对私有方法进行单元测试,但是如果私有方法对外界有UT,那么UT只能跟类型的实现是紧耦合了,这样的UT,只有写的时候才会感觉到它是多么的恶心。。。。

当然,最紧要的一点,既然承认UT的重要性了,为什么不先写UT再写产品代码呢? 明天上班给他把这个类重构掉先。

posted on 2010-01-26 23:47  施勤文  阅读(284)  评论(2编辑  收藏  举报