因为要做个小项目,同组的同事都比较年轻,为了规范下代码,因此简单的写了下怎么提高代码质量,分享一下:
在接口不通的情况下进行单元测试
使用Mockito, 如果获取余额部分代码为:
public class PayServiceImpl implements PayService {
private BizPayService bizPayService;
@Override
public BigDecimal getBalance(String pin) {
try {
return bizPayService.getBalace("", 0);
} catch (BizVirtualPayException e) {
e.printStackTrace();
}
return null;
}
public void setBizPayService(BizPayService bizPayService) {
this.bizPayService = bizPayService;
}
}
bizPayService为一个dubbo接口,如果没有提供,那么测试代码如下:
public class PayServiceTest {
@Test
public void testGetBalance() throws BizVirtualPayException{
PayServiceImpl payService = new PayServiceImpl();
BizPayService bizPayService = mock(BizPayService.class);
when(bizPayService.getBalace("", 0)).thenReturn(new BigDecimal(20.00));
payService.setBizPayService(bizPayService);
Assert.assertEquals(20.00, payService.getBalance("").doubleValue(), 0);
}
}
单元测试覆盖率
- 安装Eclemma, 安装包点击这里下载
- 安装后在eclipse中:
多了最左侧的图标
- 对测试代码右键Coverage as进行执行,执行完后:
显示该测试代码覆盖率
- 展开可见:
- 红色为未覆盖部分,说明该处代码没有测试到可能存在隐患
代码质量三驾马车之一-findbugs
静态代码缺陷检测工具
1. 对代码击右键,选择FindBugs->FindBugs,我们的开发环境中一般内置了该插件
2. 执行完成后,在代码根目录会显示找到的缺陷个数如图:
3. 打开对应的类,在左边框有如下的图标,点之:
4. 下面会出现具体的说明:
5. 对字段进行说明
Confidence 是造成缺陷的可能性, 一般为High的必须解决,这里是因为日志过滤其中使用了静态变量,而用实例方法对静态变量有可能导致并发的问题。
6. 要求
Confidence 为Hign的必须解决。
其他Confidence的必须理解其可能会造成的影响,确定不会影响系统运行时可以不解决
7. 常见问题
- 缺少空指针检查 这个不仅会造成代码缺陷,还会减少性能,因为不显示的检查空指针,JVM会动态的加进去这部分内容
- 打开资源没有在finally中关闭
- 冗余空指针检查 紧接着new 之后进行空指针检查,是没有必要的
- try{}catch空指针 通常我们的代码如下:Connection conn = null; try{conn = ..}catch(Exception e){}finally{conn.close}这个时候这个conn有可能为空。
- 用==比较对象 我们出现过这个问题,用==比较Integer导致bug
- 成员变量和局部变量同名 会导致变量被覆盖
…
代码质量三架马车之二-CheckStyle
- 对代码击右键
- Window->Show view-> CheckStyle->Checkstyle violations打开一个新的View,有所有代码规范有问题的列
- 常见问题
这个工具只有代码规范和风格的检查,一般我们需要注意:
- 空行, 删除
- 关键字之间的空格 要加,加上代码好看
- 注解相关 可以忽略
- 注释 后面单说
- 命名 常量名, 变量名,方法名。 这个要改,不改不专业
- 类长 要改,太长的类说明设计有问题
- 行长 可以通过设置eclipse Ctrl+F的动作来改
- 方法长 要改,太长说明设计有问题
- equals hashCode必须同时覆盖 这个要看HashMap的hash算法的源码部分才能理解为什么
- 成员变量和局部变量同名 会导致变量被覆盖
代码质量三家马车之三-PMD
比CheckStyle功能更强的静态代码检查工具,主要是检查一些日常编码中我们经常犯的错误,比如String,StringBuffer的滥用, 复杂度等
1. 右击代码
2. 如上左侧的小图标表示了级别, 带红x的必须解决, 其他的酌情而定
3. 常见问题
- 空方法 常见于策略,模板等模式的实现中,有的子类没有实现该方法, 这个说明算法设计有问题
- overriden注解 要加,可以利用eclipse的静态分析功能编译器发现问题
- System.out.println 要用日志代替,效率极低
- 抛出JDK自带异常 要用自定义异常代替
- 复杂度 我们定位不超过12
- could be final 忽略,这个工具想让我们把所有的变量都加上final,没有必要
- 没有用泛型 尽量使用
- 单return 忽略
- e.printStackTrace() 改为日志打印
注释要求
- public 方法必须含有详细注释
- private 方法用小方法自注释的风格保证可读性及可维护性
- 对外开放API接口要包括包注释
- 注释中方法有复杂算法的要进行说明
- 分支语句要加注释
- 要保证注释中的内容必须与代码逻辑是一致的
- 注释要对所有入参进行说明,说明取值范围,边界值,是否允许为空等
- 注释要对出参进行说明,特别是集合的情况,要说明该集合是否有肯能为null,如果没有,则用户不用再判空
- 注释对异常进行说明,说明可检异常在什么情况下会抛出
- 注释要占代码行数的20%左右,尽量达到
补充说明
- TDD。
敏捷开发最佳实践之一: 测试驱动开发。(这个有机会跟大家分享下)
这是单元测试的一个目的。 先写单元测试,用assert来确定方法的返回结果。在开发代码的时候要注意满足这个期望的结果永远是正确的,有利于设计接口,以及保持正确的返回值。
- 减少不用代码
减少复制粘贴来的大量不用代码。比如BizMessage中所使用到的APIUtils及JSONUtils 这两个类。 其中设计了JSON字符串的处理,但是实际上使用阿里巴巴的FastJSON可以直接满足要求,直接替换之,这样就不用为了这两个类写单元测试了。
在未他们写单元测试的时候才会发现他们的方法有大量没有使用的部分。
并且因为写单元测试进行覆盖率的增长是一件很麻烦的事情,会促进大家尽量写行数少的代码,以减少单元测试代码的工作量。
- 发现设计问题
在进行单元测试的时候难避免使用mock技术,当你发现一个类不好mock的时候,那么说明该类在设计上存在问题,具有不可测试性,这样的类应该修改。
- 检查代码逻辑错误
使用覆盖率工具能够检查出大量分支为红色的部分,这个说明我们的单元测试没有测试带该异常分支。同样的,我们的生产环境该分支可能是存在问题的,需要修改。
- 单元测试就是对外API文档
好的单元测试可以看做是一份接入我们API的客户端文档,比如我们写API的使用说明的时候,就可以按照我们单元测试的逻辑来写