引言
报着希望来重构。
重构代码规范
重构目标
- 让代码可读
- 让代码可测
- 消除代码警告
按照我们讨论过的《Java代码规范》进行重构代码,使代码变得可测。
需要进行以下修改:
以DictController为例
重构之前
1 |
|
重构过程
参数提取到controller层
同时在controller层验证参数,然后传给service层:
无需封装的情况
当参数个数<=7
个时。
1 |
|
需要封装参数
如果参数超过7个,则封装为Query对象
,如下:
1 |
|
然后,如果你发现该类还有一个或多个参数类似的方法:
1 |
|
则可以按多的参数来封装,这样多个方法也可以复用:
1 | public class CounterQuery { |
注意:
- 提出的对象命名:根据业务场景的对象+Query,如上面的CounterQuery
- 属性必须采用驼峰命名法,不能出现拼写错误下划线警告
- 该类放在model包的query(需新建)包下
重构后的service层如下:
1 |
|
controller现在负责接收参数:
1 |
|
返回Map对象
对于service返回封装的Map对象是不推荐的,如下:com.sinorail.base.service.impl.HomeServiceImpl#homeData
1 | map.put("vcpus_used_Count", vcpus_used_Count + ""); |
需要封装成对象:DTO(data transfer object)
:
- 放在model包的dto包下
- 封装的对象命名: 业务对象+DTO
- 成员属性命名要符合规范
service层的DAO采用构造注入
这种方式是推荐的:
- 没有警告
- 便于后面测试
1 | private final OmsLogServiceDictDao serviceDictDao; |
根据IDEA的阿里插件提示消除警告
消除代码警告
比如,这个service的new ArrayList<>()
是没有必要的,应该舍去:
1 |
|
加上类和方法注释
标注修改的时间和人,采用以下格式:
1 | /** |
命名重构
- mybatis的接口命名:XxxMapper(我们现在很多Dao,要不要改?)
- 其他参考之前讨论过的命名方式
接下来是编写单元测试,测试重构后是否正确,我们对2层编写测试:
- DAO层:包括pgsql,hbase,es等
- service层
单元测试规范
依然接着上面。
如果测试环境有单独的配置文件,则需要声明:
1 |
|
配置文件以 application-test.yml
命名。
使用Ctrl+shift+T
生成测试类,需要以下几个注意点:
覆盖的范围,采用BCDE
原则:
- B:Border,边界值测试,包括循环边界、特殊取值、特殊时间点、数据顺序等。
- C:Correct,正确的输入,并得到预期的结果。
- D:Design,与设计文档相结合,来编写单元测试。
- E:Error,强制错误信息输入(如:非法数据、异常流程、非业务允许输入等),并得
到预期的结果。
测试类和方法命名
- 测试类命名采用在后面加
Test
的命名方式 - 方法命名保持不变
1 | public class DictServiceImplTest { |
对于有些方法可以放在一起测的,只写一个方法就行,比如:
1 | public interface AssetMapper { |
可以先插入再获取判断结果:
1 |
|
这个方法的命名采用方法名+下划线连接(//TODO这个讨论)
DAO层
使用真的数据库
1 |
|
对于有修改的操作,采用事务:
1 |
|
使用内存数据库模拟
我们使用h2内存数据库.然后集成在框架里。
以下是测试环境搭建过程:
加入h2依赖
1 | <dependency> |
新增测试环境配置文件
复制一份application-dev.yml
,重命名为:application-test.yml
.内容只有数据库配置改变,以iad-web为例:
1 | spring: |
准备测试数据
就目前阶段来说,我们可以直接从数据库导出一部分数据,然后稍微修改一下,就可以给h2用了。
看上面的配置文件,有一个初始数据表的sql:init-table.sql
1 | DROP TABLE IF EXISTS assets_asset; |
还有初始化数据的:data-asset.sql:
1 | INSERT INTO assets_asset VALUES ('95c79372-ef67-4e13-8763-51de090b9d19', '192.168.17.81', 'sr-controller-1 192.168.17.81', 'sr-controller-1', '0', 'RegionFCsan', 'bc33ca7c-36a0-4b02-b81e-9b1862edf902', 'tag1', 'sr-controller-1-192.168.17.81', '2018-10-30 12:51:58.35294+08', '2018-10-30 12:51:58.35294+08', 'node', '7f482dc5-2e8d-4235-b154-3a989b5ff55c', NULL, 'controller', NULL, '1023', NULL, '[testtt3,quchunjian,openstack集群]'); |
注意点:我们导出的数据如下:
1 | DROP TABLE IF EXISTS "public"."assets_asset"; |
我们需要去除schema(也就是public)和双引号,直接替换或者写个程序转换,否则会出现语法错误
编写测试类
1 |
|
上面的批量插入报语法错误,这也是没办法的事。但基本查询都没问题。
还有需要知道的是:
1 | // 使用测试的配置文件 |
具体怎么做?
真实数据库有好处也有坏处:好处就是能得到最真实的结果。坏处就多了:比如
- 可能遇到冷启动(初始时没数据)
- 不稳定(数据会不断变化,导致测试用例不能重复执行)
- 还有一个就是慢。
内存数据库固然不错,但并不能支持pgsql的所有语法,导致有些测试无法进行。
而使用开发数据库来测是不稳定的,所以最好的办法就是有一套测试的数据库,内置一些数据来测试。
//TODO hbase, ES 等的数据构造
Service层
这一层可以经过简化,不需要加载整个应用,所以需要用到Mock对象,这是Spring自带的,
通过模拟数据库DAO层的数据,我们只关注Service层的方法。
1 | import org.junit.runner.RunWith; |
难点
- 构造测试的数据
- 保持测试代码的持久性
结语
祝大家好运!