代码覆盖的15种典型情景-1

上一篇 / 下一篇  2012-10-26 14:17:07 / 个人分类:杂谈

)R9S*VJ LU0  代码覆盖(Code Coverage)为何物?相信程序员特别是测试人 员不陌生,很多人都喜欢用代码覆盖来驱动测试的开展和完善。确实代码覆盖可以找出测试疏漏和代码问题,但是单纯的代码覆盖率高低并不能直接反映代码质量的 好坏。大多我们的努力方向都是找出那些没有覆盖到的代码,然后补充用例,完善测试。而摆在我们面前的问题是:是否我们已经充分认识到哪些不需要、不能、必 须被覆盖?只有对代码覆盖的各种情景了然于胸,才能不盲目乐观于代码覆盖率之高,悲观于代码覆盖率之低。在实践中(本文面向主要Java语言,基于 emma工具),梳理可知,对于代码覆盖我们可能都会遇到以下15种典型情景:51Testing软件测试网J1I}Fa d l

51Testing软件测试网#hVDG&l/a$z

  1、代码覆盖51Testing软件测试网~8Z!eM;T;R Y.oy

51Testing软件测试网bugd1|#LF XU

  即代码所有路径被经过,这种需要注意的是:不应该覆盖而被覆盖的情况。例如某种特殊异常就是不期望遇到的,但是遇到了,异常处理的代码也覆盖了,这时,我们应该追溯异常产生的根本原因,而不因覆盖了就直接忽略。

5X![:[je-e0

_ DE*yfn\w0  提示:不仅要关注未覆盖的代码,也要关注覆盖的,特别是偶然覆盖的代码。

^$~o r{|051Testing软件测试网@9t)]7q7TsY

  2、废弃的功能

6|v _S:bwu-R/W0D051Testing软件测试网;v4z4eT~#mS6n(C)l

  一些功能点随着产品版本不断更新,可能会被取消,这部分功能可以直接移除,保留只会让代码看起来越冗余。如果某天需要参考或找回删除的那些代码,CVS/SVN工具就搞定了。51Testing软件测试网 BC};CL.v{;].D.b

51Testing软件测试网0d_Ea,rnqT }

  提示:不用的功能不需要覆盖,要及时删除,不通过保留或者注释的方式残留在代码中。51Testing软件测试网|.z7e;k5THg

51Testing软件测试网2N:m%\:`*Ai

  3、工具类(助手类)、常量类等的私有构造器

Y K S GU9sCR]j)W051Testing软件测试网(f*lu*Wu_eM A.F ^)x

  工具类和常量类共有的特征是对外开放的都是静态方法,调用方法的时候,无需创建实例,所以推荐实践是创建一个private的构造器方法。这导致类的构造器代码无法覆盖(不考虑反射等方式)。51Testing软件测试网!h:A&]?S5n9_T5xp

51Testing软件测试网.C6l_pOA

  相反,如果某天发现对于这样的类覆盖率为100%,那检查下是否代码写的不规范:用默认构造器,然后通过实例来调用静态方法。

v.?jx da/tvr:~W0

AH4B%Q2O0  例1:工具类51Testing软件测试网,} U-Re,_W

V!b4z y,T_0public final class StringUtil {

^7D ^v$p)F'mx;OY'C)t051Testing软件测试网p!~ ?(kp~Y}

    public static String concatWithSpace(String... strings) {
s n*M;pe n S f0        return concat(MarkConstants.SPACE, strings);51Testing软件测试网Of1U8AmYTb
    }
51Testing软件测试网Kb/i+Cm

4W~^qX G gE051Testing软件测试网p%Q^v?+j
    public static String concatWithSemicolon(String... strings) {51Testing软件测试网5?{fDRt
        return concat(MarkConstants.SEMICOLON, strings);51Testing软件测试网8Cya*_$|
    }
51Testing软件测试网M#L~;^5Wc"jx}

.?:~R k } M9S3U ep!}0    private StringUtil() {51Testing软件测试网u7b(KP ^H8p&E1J
    }

5E"?pn%^'f0

:|U)q|!K1X8J0}51Testing软件测试网 E,]r8cn vz

51Testing软件测试网%^5zs7wY#})v

  例2:常量类

hqr%fB/yX#_tQX0
51Testing软件测试网4rQ+}3ux"{3b*Oq

public final class MarkConstants {
A}V6yX%Gr-B0    /**51Testing软件测试网kB4D ba#n'Du
     *{@value}
'wf%AT^tL!r0     */51Testing软件测试网&^3R_J7S/E
    public static final String SEMICOLON = ";";

[?n4@m~051Testing软件测试网*t{'Y-rgW

    private MarkConstants() {
~3sS0vq1Z;A(J d ZK0    }
51Testing软件测试网/_&q;B1sgs?l;T

51Testing软件测试网 ].hH!P C1GP

}

i)q^Z]3w9@0

dEQ1M2U1\MP0  提示:工具类(助手类)、常量类等的私有构造器不能被覆盖

rz9`)]:@M&V_Z0

Q3a(Sog,_0  4、日志级别配置51Testing软件测试网 u6s5B'bSt0p'P

Pk p;eH\b @0  日志级别不同,覆盖率高低也不同。在产品部署中,很少将日志的级别设成debug,因为日志占用磁盘空间会增长很快。只在做一些问题跟踪、调试时才会调高日志级别。

a8[*X`#\8Y6Y;jeg051Testing软件测试网 W1H0J6x+HrYfdIM!V

  所以环境使用不同的日志级别,也会导致一些日志代码没有覆盖。如以下示例程序,不打开debug级别无法覆盖部分代码:

l@ ~/T3X&S+`051Testing软件测试网Kn~ ^7c7}7z.xq,_

public static String formatPath(String path) {51Testing软件测试网V+@3t6xK
     ValidationUtil.checkString(path);
%I)T DaV$Zy]0     String returnPath = path.trim();
,R'Ad(Z!P)bV@0     if (!returnPath.startsWith(SPLIT))
~6ehAI O(Y} Hq0         returnPath = SPLIT + returnPath;51Testing软件测试网y%eH ]{b2AH*s
     if (returnPath.endsWith(SPLIT))
&P!j+}uHq0         returnPath = returnPath.substring(0, returnPath.length() - 1);
51Testing软件测试网$g RNP d,ZCb @6z9Nzc

51Testing软件测试网:?)v8f1g$l2p5f(yV

     if (LOGGER.isDebugEnabled())51Testing软件测试网jf7eSd"Yl ^
         LOGGER.debug(String
F ur2X0S&K } vAtUP(N0                 .format("[util]convert [%s] to [%s]", path, returnPath));51Testing软件测试网[4QF!~w(W*A0iP(k*y
     return returnPath;51Testing软件测试网.Z,R-nUm*k%H"[V
}

/c Vk{3LK)lb N051Testing软件测试网#\p(S&?9nI2o

  那么这部分代码需要覆盖嘛?需要。假设代码误写成:51Testing软件测试网!T5?S/lM5pL;NQ-I/p

b6Jo"P0P9[0

3@N*B{z[%u0
LOGGER.debug(String.format("[util]convert [%] to [%s]", path, returnPath));

)U%n Z r:W T0  某天日志级别设为debug,就会发现报错。类似的还有日志中经常输出某个对象信息,但是该对象可能是null,从而抛出空指针异常。51Testing软件测试网 g;s,H(q3x'mw

51Testing软件测试网7X(Ge*S#YfI

  提示:日志也是代码的一部分,需要通过调整日志级别来覆盖。51Testing软件测试网'z3p?Y4z\

in&z MR0  5、JVM等参数51Testing软件测试网7TBB3Q8fb)p%L

51Testing软件测试网T5A:?i5\

  程序的配置参数会直接影响代码路径覆盖,不仅包括业务上的一些配置,也包括依赖平台的参数,例如JVM参数除了会影响性能,也会影响代码的覆盖情况,例如断言相关参数:

[ X5r0h#d'Nu }H051Testing软件测试网5OAi _$tb? lM/tzQ

o'R)lxcIy0
-ea[:...|:] 和-da[:...|:]
51Testing软件测试网Lx}-bS;Tk2G2h+U

  分别是启用和关闭用户断言(-esa/-eda,针对系统断言),在JAVA中断言是默认关闭的,所以涉及断言的代码默认无法覆盖。

5i z9M V3A Y051Testing软件测试网1wl*UiUbGz

  提示:一些代码路径能否覆盖与JVM等参数有关,需要通过调整参数来覆盖

6n)zn0CqbCe051Testing软件测试网/zUC r2W|B8w OqT

  6、main()方法51Testing软件测试网4HI-Q(MDI

51Testing软件测试网-oD+[6k!_ |QY6k_

  一些程序员喜欢临时写一个main()方法方便于测试,完成测试后寻思以后还能方便测试就留了下来。导致产品代码中的这些代码无法被覆盖。在产品代码中,应该删除这些,部署的毕竟是产品代码,不是测试代码。51Testing软件测试网f8xtx#_T^]U%Q

^8D?&`rs(Sl0  提示:main()方不需要被覆盖,产品代码不保留测试代码51Testing软件测试网7y:yntB~o

/p-KXg2_ ch`Y0  7、编码习惯写法51Testing软件测试网)a-`|"^w;k-\a

#RdL~;v&\-['[3B3L ]0  在编码过程中,常常有一些习惯写法,最常见的比如:(1)覆盖toString()方法;(2)以意义配对形式写一些方法:比如数据连接中 Connect()搭配DisConnect(),枚举中常用的toString()搭配fromString(),这些惯用的写法告诉读者一些涵义,但 是不见得所有的方法都必须被调用,例如在产品应用中,我们可能启动起一个周期性的job,但是本身尚未添加“取消“功能(或本来就不需要停止)。自然也就 无法调用:但是它应该不应该存在?笔者认为作为完整的功能应该存在。类似的还有异常定义的时候,会定义很多重载的方法,虽然不见得每个都调用,但是不定某 天就会被调用。51Testing软件测试网SE8G1a\

!n1hS9w:I*M0  提示:编码习惯写法造成的未覆盖代码需要被覆盖,是代码的一部分。

Dl\1E$WIB/W0

!@mN6i+t0V Q-g4s.|0  8、项目的使用方式

tR2z8f4CJX!Ax6L0

#Z!N.wf\b u$_ q O5^.~0  下面两种使用方式会造成代码不能全部被覆盖:

v"c%bp1k7s051Testing软件测试网G@-Q\h._ ~qa

  1)客户端Jar方式:部分代码作为客户端Jar包形式提供给他人使用;

Zi8\s8W9\b3j051Testing软件测试网I NQ(kH8W _

  2)分布式系统交互:分布式系统之间存在交互时,例如从系统1复制文件到系统2,如果始终按照从1到2的顺序,又仅仅统计系统1的代码覆盖肯定不能覆盖全部。需要覆盖的代码虽出于一处,但是使用方式不同也会导致在不合并覆盖数据情况下代码未覆盖。51Testing软件测试网 Ba.fkf9V

"T3cb)n5?B(NI8?7HN0  提示:项目使用方式造成的代码覆盖统计数据分散需要通过合并数据来覆盖。51Testing软件测试网.lbu ^"K {3H

Q?"NH,\#XX9U0  9、常用最佳实践

t3[4X$}[ G!A`;F x0

\M8_hSMX0  一些很难覆盖的最佳实践:例如对于一些资源(IO,lock)的释放,可能直接try…catch然后记录异常,这些异常一般很难发生。51Testing软件测试网xQ#w/j_:u]

:J7V7ao'e,mh-]w(B0

4RbrEE/u$qX0
public static void close(InputStream inputStream)51Testing软件测试网r n'q u2_T"\x
{51Testing软件测试网 l0l N5u(M
         try {
$m,Xz/vhNNSQ~0             inputStream.close();
*i.CX9R+LMLd0         } catch (Exception e) {
;^n.BXu'P'f#V!_'Sv0             LOGGER.warn("fail to close inputstream");
8_)|)q @eV!g0         }51Testing软件测试网q%urBw&H#@T6E
}
51Testing软件测试网q5vU ivG5Y-V

  提示:常用最佳实践可以不覆盖。51Testing软件测试网 D$@9B&s1DtJ Q


TAG:

 

评分:0

我来说两句

Open Toolbar