package com.gustz.dove.api.service.base;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.apache.commons.lang3.time.FastDateFormat;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.GenericTypeResolver;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.sinovatech.fw.dao.HqlDao;
import com.sinovatech.fw.query.util.QueryInfo;
import com.sinovatech.fw.query.util.QueryInfoBuilder;
import com.sinovatech.fw.util.New;
/**
*
* TODO: Test base
*
* @author ZHENFENG ZHANG
* @since [Feb 4, 2015]
*
* @param <VO>
* @param <PO>
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({ "classpath:test-service-context.xml" })
public abstract class TestBase<VO extends Serializable, PO extends Serializable> {
protected final FastDateFormat dateDfmt = FastDateFormat.getInstance("yyyy-MM-dd");
protected final FastDateFormat timeDfmt = FastDateFormat.getInstance("HH:mm:ss");
protected final FastDateFormat datetimeDfmt = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss");
protected static String isDelField = "isDelete";
@Autowired
private HqlDao hqlDao;
/**
* 在测试之前做的准备工作。一般请使用这样的方式来Override:
* <pre> @Override
* public void setUp() {
* // 先调用父类的准备工作
* super.setUp();
*
* // 再调用自身的准备工作
* }
* </pre>
* @throws Exception
*/
@Before
public void setUp() throws Exception {
//null
}
/**
* 在测试完成后的清理工作。一般请使用这样的方式来Override:
* <pre> @Override
* public void tearDown() {
* // 先做自身的清理工作
*
* // 再做父类的清理工作
* super.tearDown();
* }
* </pre>
*/
@After
public void tearDown() throws Exception {
//null
}
/**
* 比较俩个VO对象是否相等。默认使用了反射方式将全部的属性转换为字符串后比较。
*
* @param loaded
* @param memoried
*/
protected void compareVo(VO loaded, VO memoried) {
String sloaded = ToStringBuilder.reflectionToString(loaded, ToStringStyle.SHORT_PREFIX_STYLE);
String smemoried = ToStringBuilder.reflectionToString(memoried, ToStringStyle.SHORT_PREFIX_STYLE);
System.out.println(sloaded);
System.out.println("");
System.out.println(smemoried);
Assert.assertEquals("数据检测结果不一样", smemoried, sloaded);
}
protected Date fmtDate(Date date) throws ParseException {
return dateDfmt.parse(dateDfmt.format(date));
}
protected Date fmtTime(Date date) throws ParseException {
return timeDfmt.parse(timeDfmt.format(date));
}
protected Date fmtDateTime(Date date) throws ParseException {
return datetimeDfmt.parse(datetimeDfmt.format(date));
}
protected BigDecimal setScale(BigDecimal bg) {
return bg.setScale(2, BigDecimal.ROUND_HALF_UP);
}
/**
* 结果集转换为字符串
*
* <pre>
* Map集合类不支持
* </pre>
* @param obj
* @return
*/
protected final String toString(Object obj) {
return ReflectionToStringBuilder.toString(obj);
}
protected void copyProperties(Object dest, Object src) {
try {
PropertyUtils.copyProperties(dest, src);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 将一组PO对象转换为VO
*
* @param pos
* @return
*/
protected List<VO> po2Vo(List<? extends PO> pos) {
List<VO> ret = New.list(pos.size());
for (PO po : pos) {
ret.add(po2Vo(po));
}
return ret;
}
/**
* 将PO对象转换为VO. <BR />
* 默认使用了反射方式,如果必要,请在子类中覆写。
*
* @param po
* @return
*/
protected VO po2Vo(PO po) {
if (po == null)
return null;
VO vo = this.<VO> insGeneric(0); //1.
copyProperties(vo, po); //2.
return vo;
}
/**
* 将一组VO对象转换为PO
*
* @param vos
* @return
*/
protected List<PO> vo2Po(List<? extends VO> vos) {
List<PO> ret = New.list(vos.size());
for (VO vo : vos) {
ret.add(vo2Po(vo));
}
return ret;
}
/**
* 将VO对象转换为PO. <BR />
* 默认使用了反射方式,如果必要,请在子类中覆写。
*
* @param vo
* @return
*/
protected PO vo2Po(VO vo) {
if (vo == null)
return null;
PO po = this.<PO> insGeneric(1); //1.
copyProperties(po, vo); //2.
return po;
}
/**
* 使用泛型定义中的第N个元素的实际绑定类型创建实例
*
* @param posi
* @return
*/
private <T> T insGeneric(int posi) {
@SuppressWarnings("unchecked")
Class<T> c = (Class<T>) GenericTypeResolver.resolveTypeArguments(getClass(), TestBase.class)[posi];
try {
return c.newInstance();
} catch (Throwable tr) {
throw new RuntimeException("Cannot create instance by Class.newInstance(): " + c.getName(), tr);
}
}
/**
* Get unique test VO
*
* @return
* @throws Exception
*/
@SuppressWarnings("unchecked")
protected VO uniqueTestVo() throws Exception {
VO vo = insGeneric(0);
PO po = insGeneric(1);
return (VO) this.listTestVos(1, vo.getClass(), po.getClass(), null, null).get(0);
}
/**
* Get unique test VO by id
*
* @param idValue
* @return
* @throws Exception
*/
protected VO uniqueTestVoById(Object idValue) throws Exception {
return uniqueTestVo(new String[] { "id" }, new Object[] { idValue });
}
/**
* Get unique test VO
*
* @param fields
* @param values
* @return
* @throws Exception
*/
@SuppressWarnings("unchecked")
protected VO uniqueTestVo(String[] fields, Object[] values) throws Exception {
VO vo = insGeneric(0);
PO po = insGeneric(1);
return (VO) this.listTestVos(1, vo.getClass(), po.getClass(), fields, values).get(0);
}
/**
* Get unique test VO
*
* @param voClass
* @param poClass
* @return
* @throws Exception
*/
protected Object uniqueTestVo(Class<?> voClass, Class<?> poClass) throws Exception {
return this.listTestVos(1, voClass, poClass, null, null).get(0);
}
/**
* Get unique test VO
*
* @param voClass
* @param poClass
* @param idValue
* @return
* @throws Exception
*/
protected Object uniqueTestVo(Class<?> voClass, Class<?> poClass, Object idValue) throws Exception {
return this.listTestVos(1, voClass, poClass, new String[] { "id" }, new Object[] { idValue }).get(0);
}
/**
* Get unique test VO
*
* @param voClass
* @param poClass
* @param fields
* @param values
* @return
* @throws Exception
*/
protected Object uniqueTestVo(Class<?> voClass, Class<?> poClass, String[] fields, Object[] values) throws Exception {
return this.listTestVos(1, voClass, poClass, fields, values).get(0);
}
/**
* Get test VO list
*
* @param limit
* @return
* @throws Exception
*/
@SuppressWarnings("unchecked")
protected <T> List<VO> listTestVos(int limit) throws Exception {
VO vo = insGeneric(0);
PO po = insGeneric(1);
return (List<VO>) this.listTestVos(limit, vo.getClass(), po.getClass(), null, null);
}
/**
* Get test VO list
*
* @param limit
* @param voClass
* @param poClass
* @return
* @throws Exception
*/
protected List<?> listTestVos(int limit, Class<?> voClass, Class<?> poClass) throws Exception {
return this.listTestVos(limit, voClass, poClass, null, null);
}
/**
* Get test VO list
*
* @param limit
* @param voClass
* @param poClass
* @param fields
* @param values
* @return
* @throws Exception
*/
protected List<?> listTestVos(int limit, Class<?> voClass, Class<?> poClass, String[] fields, Object[] values)
throws Exception {
List<Object> _voList = new ArrayList<Object>();
QueryInfo info = this.getQueryInfo(poClass, fields, values);
// do query
List<?> _list = this.hqlDao.list(info.getSql(), 1, limit, info.getParArr());
if (_list.size() > 0) {
Object _vo = null;
for (Object _po : _list) {
_vo = Class.forName(voClass.getName()).newInstance();
copyProperties(_vo, _po);
_voList.add(_vo);
}
}
return _voList;
}
/**
* Get query info
*
* @param poClass
* @param fields
* @param values
* @return
*/
private QueryInfo getQueryInfo(Class<?> poClass, String[] fields, Object[] values) {
// build HQL
QueryInfoBuilder builder = QueryInfoBuilder.ins("from " + poClass.getSimpleName() + " where 1=1 "); //
if (fields != null && fields.length > 0 && values != null && values.length > 0) {
for (int i = 0; i < fields.length; i++) {
if (isDelField.equals(fields[i])) {
continue;
}
builder.andEq(fields[i], values[i]);
}
}
if (this.getIsDelField(poClass) != null) { // is delete where
builder.andEq(isDelField, "N");
}
return builder.build();
}
/**
* Is exist field
*
* @param clazz
* @param fieldName
* @return
*/
private boolean isExistField(Class<?> clazz, String fieldName) {
for (Field _field : clazz.getDeclaredFields()) {
if (_field != null && fieldName.equals(_field.getName())) {
return true;
}
}
return false;
}
/**
* Get is delete field
*
* @param clazz
* @return
*/
private String getIsDelField(Class<?> clazz) {
if (isExistField(clazz, isDelField)) {
return isDelField;
}
return null;
}
}