1.途中碰到的问题。
这里不再详细描述,详见网友blog(http://blog.csdn.net/zxq1406spys/archive/2009/10/30/4748283.aspx)
2.上述问题解决以后,我们的单元测试环境就可以开始搭建了。
环境描述:Struts2 + Spring2.5 + hibernate3 + junit4
目的:对后台Action层的函数进行单元测试
需要的Jar包:junit4.jar(eclipse自带的,在项目路径中导入即可。“properties->Add Library->JUnit->JUnit4”)
struts2-junit-plugin-2.1.8.jar、spring-test-2.5.6.jar、spring-context-3.2.0.M2.jar
方法 | 描叙 |
executeAction(String) | 根据action的URL链接,输出action的结果流数据(结果类型不是SUCCESS,可以是FreeMarker, velocity, JSP等) |
getActionProxy(String) | 生成一个action的代理 |
injectStrutsDependencies(object) | 注入一个依赖对象 |
getActionMapping(String) | 获得ActionMapping |
findValueAfterExecute(String) | action执行之后,从值栈中取值 |
|
|
属性 | 描叙 |
MockHttpServletRequest request | requset传递给struts2 |
MockHttpServletResponse response | 用于测试struts2输出 |
MockServletContext servletContex | The servlet context 传递给struts2 |
import javax.servlet.http.HttpServletRequest; import org.apache.struts2.StrutsSpringTestCase; import org.hibernate.FlushMode; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.dao.DataAccessResourceFailureException; import org.springframework.orm.hibernate3.SessionFactoryUtils; import org.springframework.orm.hibernate3.SessionHolder; import org.springframework.transaction.support.TransactionSynchronizationManager; import bijian.controller.action.UserAction; public class UserActionTest extends StrutsSpringTestCase { /*这个函数相当@Before注解的函数,是调用单元测试后的时候, 首先会执行的方法。可以在这里面做一些必要的准备工作*/ @Override protected void setUp() throws Exception { super.setUp(); SessionFactory sessionFactory = lookupSessionFactory(this.request); Session hibernateSession= getSession(sessionFactory); TransactionSynchronizationManager.bindResource(sessionFactory,new SessionHolder(hibernateSession)); } private Session getSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException { Session session = SessionFactoryUtils.getSession(sessionFactory, true); FlushMode flushMode = FlushMode.NEVER; if (flushMode != null) { session.setFlushMode(flushMode); } return session; } private SessionFactory lookupSessionFactory(HttpServletRequest request) { //“sessionFactory”是你spring配置文件(通常是application.xml)中的SessionFactory。 //如:org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean return (SessionFactory)this.applicationContext.getBean("sessionFactory"); } /*这个是单元测试的方法,一个方法测试一个功能,或者一个action*/ public void testGetReceiveMessage() throws Exception { /*request是类StrutsSpringTestCase的成员变量, 是MockHttpServletRequest对象,在这里mock出来的一个web中的request*/ this.request.setParameter("userId", "1"); /*我的环境中,返回值是json格式,result将是json格式的一个字符串输入action的地址*/ String result = executeAction("/modules/train/messageAction!getReceiveMessage.action"); } }
这样关于lazy加载的问题解决。其实这个时限还是参考了Spring中OpenSessionInViewFilter的。
首先,通过lookupSessionFactory()函数来获取这个测试环境中的org.hibernate.SessionFactory实体对象,其中的applicationContext是org.springframework.context.ApplicationContext的实现org.springframework.context.support.GenericApplicationContext,我们可以通过它的getBean方法来获取你配置文件中配置的SessionFactory。使用注解是org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean,不需要使用注解的时候可以用org.springframework.orm.hibernate.LocalSessionFactoryBean来实现。
然后,在通过getSession()来获取其中的一个session,获取session的过程类似于java jdk 1.4以后的ThreadLocal类的实现方法,为每一个线程(用户的每一个request请求)提供一个“私有的”session实体类。关于ThreadLocal是干什么的,这里就不多讲了。所以我们在获取Session的时候,将这个session的FlushMode设置为FlushMode.NEVER,这样就可以让Spring来管理这个session,使得hibernate查询结束后,不会关闭session,从而解决lazy加载的问题。
最后,调用Spring提供的TransactionSynchronizationManager.bindResource()方法将session绑定到该请求的resources中,值得一提的是,其中的resources也是通过ThreadLocal来实现跟线程绑定的。
关于实现web session的问题,很简单,该类提供了一个MockHttpServletRequest成员变量,我们只要mock一个session出来,然后加入到这个request中,就可以实现session的模拟了。示例代码如下:
HttpSession session = new MockHttpSession(); String sessionId = UUID.randomUUID().toString(); session.setAttribute(ConstParameter.USER_SESSION, sessionId); //user是一个用户信息的类,你可以根据你的需要自己定义 UserInfor user = new UserInfo(); user.setUserId(1); user.setName("xxx"); session.setAttribute(ConstParameter.USER_INFO, user); request.setSession(session);
这样,我们的单元测试功能就可以用了。
注:在文中,需要加载spring配置文件信息,默认加载的路径是你项目的src目录下,文件名默认为“application.xml”,如果你的spring配置文件放在其它的目录下,或者文件的名字跟默认的不相符,那么你需要重载StrutsSpringTestCase类中的getContextLocations()函数。代码如下:
@Override public String getContextLocations() { //返回你项目中spring配置文件所在的目录 return "/tutorial/action/TestAccountAction-context.xml"; }