网站后端一般从下往上有Entity层(对应DB table) —> Dao层(对应DB table增删改查各种操作)—> Service层(业务逻辑层,调用dao层和DB打交道) —> Controller层(对应各种http api,调用service)。
前后端分离开发的话,后端必须做到充分的自测,才能保证前后端联调时不出大问题。如果Dao层使用JPA的话,其实不需要测试,除非用错了。那么,针对entity层和service/controller层,后端开发时怎么自测一直是个问题萦绕在我心头。
目前这个问题的一半找到了答案,可以使用Hibernate Session对entity类进行测试。如果entity类的字段定义或者注解不合理的话,增删改查操作会报错,那么上层的service/controller也就会出错。所以entity层的测试其实十分必要。在测试过程中,将hibernate配置成打印sql语句,并且在实际unit test的catch子句里打印stack trace十分实用,能快速定位问题。
步骤总结如下,供日后参考:
- 首先在src/main/resource下增加配置文件hibernate.cfg.xml,配置数据库driver,dialect,数据库连接url,用户名,密码等等,记得把需要测试的entity类配置到mapping节点里,class=“完整包名.entity类名”
有时候为了省事儿,也可以不配置这个文件,直接在HibernaterUtil类里,创建SessionFactory实例时把各项配置塞进去。下一步代码里会有示例。
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://dburl/auto</property>
<property name="hibernate.connection.username">DB用户名</property>
<property name="hibernate.connection.password">DB密码</property>
<property name="hibernate.connection.pool_size">1</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<property name="hbm2ddl.auto">update</property>
<mapping class="com.ssophie.xxxentiry"/>
<mapping class="com.ssophie.oooentity"/>
</session-factory>
</hibernate-configuration>
- HibernateUtil.class
如果走hibernate.cfg.xml的话,代码异常简单,一句话的事儿:sessionFactory = new Configuration().configure().buildSessionFactory();
。
不走hibernate.cfg.xml的话呢,就把每个配置项塞进去:
Configuration configuration = new Configuration().configure().buildSessionFactory();
.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect")
.setProperty("hibernate.connection.driver_class", "com.mysql.cj.jdbc.Driver")
.setProperty("hibernate.connection.url", "DBUrl...").setProperty("hibernate.connection.username","oooo")
.setProperty("hibernate.connection.password", "xxxx");
ServiceRegistry serviceRegistry
= new StandardServiceRegistryBuilder()
.applySettings(configuration.getProperties()).build(); configuration.addAnnotatedClass(entity_xxx.class).addAnnotatedClass(entity_ooo.class);
sessionFactory = configuration
.buildSessionFactory(serviceRegistry);
完整的HibernateUtil类代码如下,创建SessionFactory实例之后,使用sessionFactory.openSession()就可以拿到一个session.
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import com.ssc.ssgx.web.entities.xxx;
import com.ssc.ssgx.web.entities.ooo;
public class HibernateUtil {
private static SessionFactory sessionFactory = null;
static {
try{
loadSessionFactory();
}catch(Exception e){
System.err.println("Exception while initializing hibernate util.. ");
e.printStackTrace();
}
}
public static void loadSessionFactory(){
sessionFactory = new Configuration().configure().buildSessionFactory();
/**
Configuration configuration = new Configuration().configure().buildSessionFactory();
.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect")
.setProperty("hibernate.connection.driver_class", "com.mysql.cj.jdbc.Driver")
.setProperty("hibernate.connection.url", "DBUrl...").setProperty("hibernate.connection.username","oooo")
.setProperty("hibernate.connection.password", "xxxx");
ServiceRegistry serviceRegistry
= new StandardServiceRegistryBuilder()
.applySettings(configuration.getProperties()).build(); configuration.addAnnotatedClass(entity_xxx.class).addAnnotatedClass(entity_ooo.class);
sessionFactory = configuration
.buildSessionFactory(serviceRegistry);**/
}
public static Session getSession() throws HibernateException {
Session retSession=null;
try {
retSession = sessionFactory.openSession();
}catch(Throwable t){
System.err.println("Exception while getting session.. ");
t.printStackTrace();
}
if(retSession == null) {
System.err.println("session is discovered null");
}
return retSession;
}
}
- 测试类里,在BeforeClass里获取session,然后执行各个test单元,最后在AfterClass里关闭session即可。如果是进行删除修改测试的话,记得tansaction要commit…
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.ssc.ssgx.web.entities.CaseInfo;
public class CaseInfoTest {
private static Session session;
@BeforeClass
public static void getSession(){
session = HibernateUtil.getSession();
}
@Test
public void TestAddCase() {
Transaction transaction = null;
try {
transaction = session.beginTransaction();
CaseInfo caseInfo = new CaseInfo();
caseInfo.setCaseDesc("xxx");
caseInfo.setCaseId("xxx");
session.save(caseInfo);
transaction.commit();
} catch (Exception exception) {
System.out.println(exception.getMessage());
transaction.rollback();
}
}
@Test
public void deleteCase(){
Transaction transaction = null;
try {
transaction = session.beginTransaction();
CaseInfo c = session.get(CaseInfo.class, Long.valueOf(6l));
session.delete(c);
transaction.commit();
} catch (Exception exception) {
System.out.println(exception.getMessage());
transaction.rollback();
}
}
@AfterClass
public static void closeSession(){
if(session != null)
session.close();
}
}