使用MockEJB测试SessionBean及数据库应用
【IT168 技术文档】
J2EE应用中对于EJB的单元测试是很麻烦的,需要写完EJB后再打包、部署、测试出问题后再次修改、打包、部署……而打包、部署的时间往往是最浪费时间的,MockEJB可以帮助我们省略这2步,编译完成后即可运行,调试方法跟普通的Javabean类似。
MockEJB其实模拟了一个mini J2EE容器,对ejb的mock操作都在该虚拟容器内部执行,能够满足绝大部分的EJB功能测试。为了更方便的使用MockEJB,我们可以对其中常用的绑定、部署功能进行封装。
import org.mockejb.OptionalCactusTestCase;
import org.mockejb.MockContainer;
import org.mockejb.SessionBeanDescriptor;
import org.mockejb.jndi.MockContextFactory;
import javax.naming.Context;
import javax.naming.InitialContext;
import java.util.StringTokenizer;
import net.sf.hibernate.cfg.Configuration;
import net.sf.hibernate.SessionFactory;
import com.mockrunner.mock.ejb.
MockUserTransaction;
import junit.framework.TestCase;
/**
* 使用MockEJB做测试时的辅助类,
* 封装了常用的deploy和bind方法。
* 用自己的测试类继承该抽象类。
* <p/>
* @author lucene
* @version 1.0 2004-12-15 10:26:33
*/
public abstract class AbstractMockEJBTest
extends TestCase
{
private Context context;
private MockContainer mockContainer;
/**
* 初始化上下文环境。
*/
protected void setUp() throws Exception
{
MockContextFactory.setAsInitial();
context = new InitialContext();
mockContainer =
new MockContainer(context);
}
/**
* 取得上下文环境
*
* @return 上下文环境
*/
protected Context getContext()
{
return context;
}
/**
* 把指定的SessionBean部署到
Mock的容器环境中。
*
* @param jndi JNDI名称
* @param home 主接口
* @param remote 远程接口
* @param bean 实现类
* @throws Exception
*/
public void deploySessionBean
(String jndi, Class home, Class
remote, Class bean)
throws Exception
{
SessionBeanDescriptor descriptor =
new SessionBeanDescriptor
(jndi, home, remote, bean);
mockContainer.deploy(descriptor);
}
/**
* 绑定数据源到上下文环境,
这里默认提供的是Oracle的数据源,
* 如果是MySQL,那么数据源就使用:
* <code>com.mysql.jdbc.jdbc2.optional.
MysqlDataSource</code>
* 如果使用其他的数据库连结池来获取
数据源则无需调用该方法。
*
* @param jndi JNDI名称
* @param url JDBC URL
* @param user 用户名
* @param password 密码
* @throws Exception
*/
public void bindDataSource
(String jndi, String url,
String user, String password)
throws Exception
{
oracle.jdbc.pool.OracleDataSource
ds = new oracle.jdbc.pool
.OracleDataSource();
ds.setURL(url);
if(user != null) ds.setUser(user);
if(password != null)
ds.setPassword(password);
context.rebind(jndi, ds);
}
/**
* 绑定<code>SessionFactory
</code>到指定的JNDI名称
* @param jndi JNDI名称
* @param cfgFiles 配置文件,
中间用半角逗号隔开
* @throws Exception
*/
public void bindHibernate
(String jndi, String cfgFiles)
throws Exception
{
StringTokenizer st =
new StringTokenizer(cfgFiles, ",");
Configuration cfg = new Configuration();
while(st.hasMoreTokens()) {
String cfgFile = st.nextToken().trim();
cfg.configure(cfgFile);
}
SessionFactory sf =
cfg.buildSessionFactory();
context.rebind(jndi, sf);
}
/**
* 绑定事务处理到JNDI。
*
* @param trans
MockEJB的<code>MockUserTransaction</code>类
* @throws Exception
*/
public void bindTransaction
(MockUserTransaction trans)
throws Exception
{
if(trans == null)
trans = new MockUserTransaction();
context.rebind
("javax.transaction.UserTransaction",
trans);
}
public void tearDown()
{
MockContextFactory.revertSetAsInitial();
}
}
接下来的单元测试工作就很轻松啦,例如:
public class XXXUnitTest
extends AbstractMockEJBTest
{
private ResourceServiceManager
resServiceManager;
private ResourceServiceManagerHome
resServiceManagerHome;
public void setUp() throws Exception
{
super.setUp();
super.deploySessionBean
(ResourceServiceManagerHome.JNDI_NAME,
ResourceServiceManagerHome.class,
ResourceServiceManager.class,
ResourceServiceManagerBean.class);
super.deploySessionBean
(ResourceStockManagerHome.JNDI_NAME,
ResourceStockManagerHome.class,
ResourceStockManager.class,
ResourceStockManagerBean.class);
super.bindDataSource("xxxx3ds",
"jdbc:oracle:thin:
@dbserver:1521:orcl", "user", "pass");
super.bindHibernate
("hibernate/session_factory",
"/xxx.cfg.xml, /xxx1.cfg.xml,
/xxx2.cfg.xml");
super.bindTransaction(mockTransaction);
resServiceManagerHome =
(ResourceServiceManagerHome)
super.getContext().lookup
(ResourceServiceManagerHome.JNDI_NAME);
resServiceManager =
resServiceManagerHome.create();
}
public void testXXXXXX()
throws Exception {
Collection result =
resServiceManager.getXXXXXX();
assertNotNull(result);
}
}
修改ResourceServiceManagerBean后不需要重新打包、部署EJB,直接编译,然后再次运行单元测试就能看到更新后的结果了。