欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

开发和测试业务逻辑问题集

程序员文章站 2022-04-25 22:13:48
...
每次在开发和测试业务逻辑biz时老是碰到这样那样似曾相识的问题,现在记一下备忘。
1、使用JPA/Hibernate/Ebean等ORM时来存取数据库时,不另外增加DAO层。理由是ORM已经封装和统一了不同数据库的基础访问、存取操作,不需要重复劳动,除非有特殊需要。

2、事务处理就是在biz层上定义的,推荐使用Spring容器来管理事务。

3、在使用事务注解时要注意@Transactional注解只能使用在public方式上才有效。放在protected/private方法上不会报错。另外只需要在要启动事务的最外层方法上加这个注解,内部方法是不需要的。

4、在对查询数据库操作,应使用只读事务,对数据加共享锁,以避免其他事务修改该数据。同时注意注解应使用这种形式:
@Transactional(propagation=Propagation.REQUIRED, readOnly=true)
使用Propagation.REQUIRED以确保事务的正常启动,如果使用propagation=Propagation.NOT_SUPPORTED则不会启动事务,readOnly属性实际上就失效了。

5、在使用Spring来管理Ebean的事务时,记得要设置<property name="defaultServer" value="true" />。否则死活不会成功。Ebean的Spring例子上好像有错。

6、在使用Spring来管理事务时,有两种生成代理方式。默认是Jdk自带的代理实现。推荐cglib方式,因为这种方式是使用的enhancer代理方式,是在原有XXXBizImpl上产生了一个增强的继承类,所以代理对象可以转换成XXXBizImpl。这样在测试时就更方便。因为我们业务接口方法肯定少于实现的方法。要测试实现上的各个方法,只有用cglib才能注入实现类。Jdk proxy只能注入接口。
要使用cglib除了增加相关依赖包,还要在spring中增加<aop:config proxy-target-class="true" />。
至于两种方式的性能,可参考http://budairenqin.iteye.com/blog/1500366,如果被测的cglib版本比较低。

7、使用unitils来对biz层进行测试,并使用dbunit来初始化测试数据。使用dbunit也会有几个问题:
使用@ExpectedDataSet注解时,会出现org.dbunit.dataset.RowOutOfBoundsException: 1 > (1)异常,但不影响结果,只需要换用新版本的dbunit就行了。出错的版本是dbunit2.2.2。
(2)在配置Spring事务后,本来测试时还正常的dataset测试文件,会报出org.dbunit.dataset.NoSuchColumnException: HIP_PERSON.BASIC_ADDR_ID - (Non-uppercase input column: BASIC_ADDR_ID) in ColumnNameToIndexes cache map. Note that the map's column names are NOT case sensitive.异常。
出错的原因是第一条测试数据有8个字段,第二条测试数据只有3个,dbnit会用第一条数据的字段去要求第二条数据的,结果就报错了。结果这不是一个bug,可以看这里http://www.dbunit.org/components.html#flatxmlDataSet,
如果要想测试通过,需要把每条记录的字段都弄成一样多,但是这样太麻烦了。unitils也一直未更新解决该问题。结果只有自己重写了MultiSchemaXmlDataSetFactory。另:可自己通过DatabaseUnitils类来生成DataSet的XSD。
(3)需要注意的@ExpectedDataSet注解只验证dataset xml文件中对应的数据。不对数据库所有的数据进行验证。

8、在使用Spring管理事务时,会碰到Service/Biz实现类因调用自身方法而导致事务错误的情况。如下:

Class ABiz{
@Resource
private bBiz;
@Transaciton
public void add(){}

public void addAll(){
this.add(); //这里因为直接调用的this.add(),所以spring代理并不启动事务
bBiz.xxx(); //这里的事务有效
}
}

所以,需要在ABiz中注入自身,通过spring代理来调用带事务的业务方法。
代码修改如下:

Class ABiz{
@Resource
private bBiz;

@Resource
private aBiz;

@Transaciton
public void add(){}

public void addAll(){
aBiz.add(); //现在,事务注解就生效了
bBiz.xxx(); //这里的事务有效
}
}
相关标签: 测试 unitils