分享
 
 
 

用Cactus来测试J2ee应用

王朝java/jsp·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

用Cactus来测试J2ee应用

内容:

介绍

介绍

参考资料

关于作者

--

相关内容:

TCP/IP 介绍

TCP/IP 介绍

--

Java 专区中还有:

教学

工具与产品

代码与组件

所有文章

实用技巧

韩伟 (java_cn@21cn.com)

北京某公司系统分析员

2002 年 8 月

Junit是当前最流行的测试框架,它能够让开发人员很方便的编写测试单元,可以使他们"放心"地开发。但是现在很多的应用都是基于j2ee的,代码都是在服务器端的容器里面运行,这个使测试带来了一些麻烦。对于普通的jsp,servlet用Junit来测试好像已经不是那么方便,对于EJB来说,特别是2.0版本,很多接口都是Local Interface,没有办法进行分布式的测试。那么我们如何进行这些代码的测试呢?Apache为我们提供了一个强大的工具 Cactus!它是一套简单,易于使用的服务器端测试框架,可以使开发人员很轻松的测试服务器端的程序,他们会说:"哦,就是这么简单"。Cactus是Junit的一个扩展,但是它又和Junit有一些不同。Cactus的测试分为三种不同的测试类别,JspTestCase,ServletTestCase,FilterTestCase,而不是像Junit就一种TestCase。Cactus的测试代码有服务器端和客户端两个部分,他们协同工作。那我们为什么不用Junit来做测试呢?主要有一下几个理由:

EJB2.0中的Local interface ,不允讯远程调用。用Junit不好测试,而Cactus的redirector位于服务器端,可以和EJB运行在一个容器中,这使得它可以直接访问Local Interface。

一般EJB或者servlet,jsp都是运行在服务器上,如果你使用junit测试的话,你的测试是在客户端,这使的运行环境和测试环境处于不同的系统环境中,这个有时候会不同的测试结果。

在一个EJB的应用中,一般都会有一些前端应用来访问EJB,例如:jsp,servlet,javabean。这就意味着你需要一个测试框架来测试这些前端的组件。Cactus提供了所有这些组件的测试方法。哦,太棒了。

Cactus和ant很好的结合在一起,可以很容易的完成自动化测试,减少了很多工作量。当然,junit也提供这样的支持。

前面是对Cactus作了一个大致的介绍,接下来我们用一个实际的例子来运用一下这个强大的测试框架。首先我们需要一个被测试的对象,在这里我们选用EJB2.0 CMP.我们做一个简单的用户管理。一下就一些主要的代码,来进行一些分析。

UserHome.java

package usersystem;

import javax.ejb.*;

import java.util.*;

public interface UserHome extends javax.ejb.EJBLocalHome {

public User create(String name, String password) throws CreateException;

public Collection findAll() throws FinderException;

public User findByPrimaryKey(String name) throws FinderException;

}

User.java

package usersystem;

import javax.ejb.*;

import java.util.*;

public interface User extends javax.ejb.EJBLocalObject {

public String getName();

public void setPassword(String password);

public String getPassword();

public void setUserInfo(UserInfo userInfo);

public UserInfo getUserInfo();

public void setName(String name);

}

UserInfoHome.java

package usersystem;

import javax.ejb.*;

import java.util.*;

public interface UserInfoHome extends javax.ejb.EJBLocalHome {

public UserInfo create(String name, String email, String address, String tel) throws

CreateException;

public UserInfo findByPrimaryKey(String name) throws FinderException;

}

这里有两个Entity Bean用来创建用户信息。他们之间的关系在xml部署描述文件中描述,他们是1对1的关系。

UserManagerLocal.java

package usersystem;

import javax.ejb.*;

import java.util.*;

public interface UserManagerLocal extends javax.ejb.EJBLocalObject {

public void addUser(String name, String password, String email, String address, String tel);

public Collection findAll() ;

public void delAll();

public void delByName(String name);

public User findByName(String name) ;

}

UserManagerBean.java

package usersystem;

import javax.ejb.*;

import javax.rmi.PortableRemoteObject;

import javax.naming.*;

import java.util.*;

public class UserManagerBean implements SessionBean {

SessionContext sessionContext;

public void ejbCreate() throws CreateException {

/**@todo Complete this method*/

}

public void ejbRemove() {

/**@todo Complete this method*/

}

public void ejbActivate() {

/**@todo Complete this method*/

}

public void ejbPassivate() {

/**@todo Complete this method*/

}

public void setSessionContext(SessionContext sessionContext) {

this.sessionContext = sessionContext;

}

/**

* 添加用户

* @param name 用户姓名

* @param password 密码

* @param email 电子邮件

* @param address 地址

* @param tel 电话

*/

public void addUser(String name, String password, String email, String address, String tel) {

try{

UserHome userHome=getUserHome();

User user=userHome.create(name,password) ; //create user entity

UserInfoHome userInfoHome=getUserInfoHome();

UserInfo userInfo=userInfoHome.create(name,email,address,tel) ;// create userinfo

entity

user.setUserInfo(userInfo) ;

}catch(Exception e){

throw new javax.ejb.EJBException (e.toString());

}

}

/**

* 返回UserHome接口

* @return userHome

*/

private UserHome getUserHome(){

try {

javax.naming.InitialContext ctx=new javax.naming.InitialContext ();

Object ref = ctx.lookup("User");

//cast to Home interface

UserHome userHome = (UserHome) PortableRemoteObject.narrow(ref, UserHome.class);

return userHome;

}

catch (ClassCastException ex) {

ex.printStackTrace() ;

return null;

}catch (NamingException ex) {

ex.printStackTrace() ;

return null;

}

}

/**

* 返回UserInfoHome接口

* @return

*/

private UserInfoHome getUserInfoHome(){

try {

javax.naming.InitialContext ctx=new javax.naming.InitialContext ();

Object ref = ctx.lookup("UserInfo");

//cast to Home interface

UserInfoHome userInfoHome = (UserInfoHome) PortableRemoteObject.narrow(ref,

UserInfoHome.class);

return userInfoHome;

}

catch (ClassCastException ex) {

throw new EJBException();

}catch (NamingException ex) {

throw new EJBException(ex.toString());

}

}

/**

* 返回所有用户记录

* @return c

* @throws javax.ejb.FinderException

*/

public java.util.Collection findAll() {

Collection c = null;

try {

UserHome uh=this.getUserHome() ;

c=uh.findAll() ;

}

catch (FinderException ex) {

throw new javax.ejb.EJBException ();

}

return c;

}

/**

* 删除所有记录

*/

public void delAll(){

try {

UserHome u=getUserHome();

java.util.Collection c=u.findAll() ;

java.util.Iterator i=c.iterator() ;

while(i.hasNext() ){

u.remove(((User)i.next()).getName()) ;

}

}

catch (Exception ex) {

throw new EJBException(ex.toString());

}

}

/**

* 根据用户名删除记录

* @param name

*/

public void delByName(String name) {

try {

User user=findByName(name);

UserHome uh=getUserHome();

uh.remove(user.getName()) ;

}

catch (Exception ex) {

throw new javax.ejb.EJBException (ex.toString());

}

}

/**

* 通过用户名查找用户记录

* @param name

* @return

*/

public User findByName(String name) {

try {

UserHome uh=this.getUserHome() ;

User user=(User)uh.findByPrimaryKey(name) ;

UserHome u=this.getUserHome() ;

User uu=u.findByPrimaryKey(name) ;

return user;

}

catch (FinderException ex) {

throw new EJBException(ex.toString());

}

}

}

UserManagerBean是一个session bean ,它主要是对user的管理,和客户端通讯,其实就是session facade模式 。代码里面有注释,这里就不多叙述了。

ejb-jar.xml 部署文件描述

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN"

"http://java.sun.com/dtd/ejb-jar_2_0.dtd">

<ejb-jar>

<enterprise-beans>

<session>

<display-name>UserManager</display-name>

<ejb-name>UserManager</ejb-name>

<local-home>usersystem.UserManagerLocalHome</local-home>

<local>usersystem.UserManagerLocal</local>

<ejb-class>usersystem.UserManagerBean</ejb-class>

<session-type>Stateless</session-type>

<transaction-type>Container</transaction-type>

<ejb-local-ref>

<description />

<ejb-ref-name>User</ejb-ref-name>

<ejb-ref-type>Entity</ejb-ref-type>

<local-home>usersystem.UserHome</local-home>

<local>usersystem.User</local>

<ejb-link>User</ejb-link>

</ejb-local-ref>

<ejb-local-ref>

<description />

<ejb-ref-name>UserInfo</ejb-ref-name>

<ejb-ref-type>Entity</ejb-ref-type>

<local-home>usersystem.UserInfoHome</local-home>

<local>usersystem.UserInfo</local>

<ejb-link>UserInfo</ejb-link>

</ejb-local-ref>

</session>

<entity>

<display-name>User</display-name>

<ejb-name>User</ejb-name>

<local-home>usersystem.UserHome</local-home>

<local>usersystem.User</local>

<ejb-class>usersystem.UserBean</ejb-class>

<persistence-type>Container</persistence-type>

<prim-key-class>java.lang.String</prim-key-class>

<reentrant>False</reentrant>

<cmp-version>2.x</cmp-version>

<abstract-schema-name>User</abstract-schema-name>

<cmp-field>

<field-name>name</field-name>

</cmp-field>

<cmp-field>

<field-name>password</field-name>

</cmp-field>

<primkey-field>name</primkey-field>

<query>

<query-method>

<method-name>findAll</method-name>

<method-params />

</query-method>

<ejb-ql>select Object(theUser) from User as theUser</ejb-ql>

</query>

</entity>

<entity>

<display-name>UserInfo</display-name>

<ejb-name>UserInfo</ejb-name>

<local-home>usersystem.UserInfoHome</local-home>

<local>usersystem.UserInfo</local>

<ejb-class>usersystem.UserInfoBean</ejb-class>

<persistence-type>Container</persistence-type>

<prim-key-class>java.lang.String</prim-key-class>

<reentrant>False</reentrant>

<cmp-version>2.x</cmp-version>

<abstract-schema-name>UserInfo</abstract-schema-name>

<cmp-field>

<field-name>name</field-name>

</cmp-field>

<cmp-field>

<field-name>email</field-name>

</cmp-field>

<cmp-field>

<field-name>address</field-name>

</cmp-field>

<cmp-field>

<field-name>tel</field-name>

</cmp-field>

<primkey-field>name</primkey-field>

</entity>

</enterprise-beans>

<relationships>

<ejb-relation>

<ejb-relation-name>userInfo-user</ejb-relation-name>

<ejb-relationship-role>

<description>userInfo</description>

<ejb-relationship-role-name>UserInfoRelationshipRole</ejb-relationship-role-name>

<multiplicity>One</multiplicity>

<cascade-delete />

<relationship-role-source>

<description>userInfo</description>

<ejb-name>UserInfo</ejb-name>

</relationship-role-source>

<cmr-field>

<description>user</description>

<cmr-field-name>user</cmr-field-name>

</cmr-field>

</ejb-relationship-role>

<ejb-relationship-role>

<description>user</description>

<ejb-relationship-role-name>UserRelationshipRole</ejb-relationship-role-name>

<multiplicity>One</multiplicity>

<relationship-role-source>

<description>user</description>

<ejb-name>User</ejb-name>

</relationship-role-source>

<cmr-field>

<description>userInfo</description>

<cmr-field-name>userInfo</cmr-field-name>

</cmr-field>

</ejb-relationship-role>

</ejb-relation>

</relationships>

<assembly-descriptor>

<container-transaction>

<method>

<ejb-name>User</ejb-name>

<method-name>*</method-name>

</method>

<trans-attribute>Required</trans-attribute>

</container-transaction>

<container-transaction>

<method>

<ejb-name>UserManager</ejb-name>

<method-name>*</method-name>

</method>

<trans-attribute>Required</trans-attribute>

</container-transaction>

<container-transaction>

<method>

<ejb-name>UserInfo</ejb-name>

<method-name>*</method-name>

</method>

<trans-attribute>Required</trans-attribute>

</container-transaction>

</assembly-descriptor>

</ejb-jar>

接下来是访问EJB的客户端,我们用了一个servlet.

ManaServlet.java

package usersystem.servlet;

import javax.servlet.*;

import javax.servlet.http.*;

import java.io.*;

import java.util.*;

import usersystem.*;

import javax.naming.*;

import javax.ejb.*;

import javax.ejb.*;

import javax.ejb.*;

/**

* <p>Title: </p>

* <p>Description: </p>

* <p>Copyright: Copyright (c) 2002</p>

* <p>Company: </p>

* @author unascribed

* @version 1.0

*/

public class ManaServlet extends HttpServlet {

static final private String CONTENT_TYPE = "text/html; charset=GBK";

private UserManagerLocalHome h=null;

private UserManagerLocal uml=null;

public void init() throws ServletException{

try {

h=getHome();

uml=h.create() ;

}

catch (CreateException ex) {

ex.printStackTrace() ;

}

}

public void doGet(HttpServletRequest request, HttpServletResponse response) throws

ServletException, IOException {

}

public void doPost(HttpServletRequest request, HttpServletResponse response) throws

ServletException, IOException {

}

public void addUser(HttpServletRequest request, HttpServletResponse response) throws

javax.ejb.EJBException {

String name=request.getParameter("name") ;

String tel=request.getParameter("tel") ;

String address=request.getParameter("address") ;

String email=request.getParameter("email") ;

String pass=request.getParameter("pass") ;

uml.addUser(name,pass,email,address,tel) ;

}

public User findByName(String name) throws javax.ejb.EJBException {

User u = null;

u=uml.findByName(name) ;

return u;

}

public java.util.Iterator findAll() throws javax.ejb.EJBException {

java.util.Collection c=uml.findAll() ;

return c.iterator() ;

}

public void delAll() throws javax.ejb.EJBException {

uml.delAll() ;

}

public void delUser(String name) throws javax.ejb.EJBException {

uml.delByName(name) ;

}

public UserManagerLocalHome getHome() {

UserManagerLocalHome home = null;

try {

javax.naming.InitialContext ctx=new javax.naming.InitialContext ();

home=(UserManagerLocalHome)ctx.lookup("UserManagerLocal") ;

}

catch (NamingException ex) {

ex.printStackTrace() ;

return null;

}

return home;

}

public void destroy() {

}

}

这个servlet在doGet,doPost没有实现任何方法,这个不影响我们测试,我们要测试的只是这些public method. 我们的测试代码如下:

package usersystem.test;

/**

* <p>Title: </p>

* <p>Description: </p>

* <p>Copyright: Copyright (c) 2002</p>

* <p>Company: </p>

* @author unascribed

* @version 1.0

*/

import usersystem.servlet.*;

import java.io.IOException;

import java.net.URLDecoder;

import java.util.Hashtable;

import junit.framework.Test;

import junit.framework.TestSuite;

import org.apache.cactus.Cookie;

import org.apache.cactus.ServletTestCase;

import org.apache.cactus.WebRequest;

import org.apache.cactus.WebResponse;

import javax.ejb.*;

import javax.servlet.*;

import usersystem.*;

public class ManaServletTest extends ServletTestCase{

ManaServlet servlet=new ManaServlet();

public ManaServletTest(String theName) {

super(theName);

}

public void setUp(){

try {

servlet.init() ;

}

catch (ServletException ex) {

ex.printStackTrace() ;

this.fail() ;

}

}

public void tearDown(){

}

public void beginAddUser(WebRequest theRequest)

{

theRequest.addParameter("name", "nameValue");

theRequest.addParameter("pass","passValue") ;

theRequest.addParameter("tel","telValue") ;

theRequest.addParameter("address","addressValue") ;

theRequest.addParameter("email","emailValue");

}

public void testAddUser() throws javax.ejb.EJBException{

servlet.addUser(request,response) ;

}

public void testFindAll(){

java.util.Iterator i=servlet.findAll() ;

//assertEquals(null,i);

boolean ok=false;

while(i.hasNext() ){

if(((User)i.next()).getName().equals("nameValue")) {

ok=true;

};

}

this.assertTrue(ok) ;

}

public void testFindByName() throws javax.ejb.EJBException {

User u=servlet.findByName("nameValue") ;

UserInfo ui=u.getUserInfo() ;

this.assertEquals("email",ui.getEmail()) ;

this.assertEquals("tel",ui.getTel()) ;

this.assertEquals("nameValue",u.getName()) ;

this.assertEquals("passValue",u.getPassword()) ;

}

public void testDel() throws javax.ejb.EJBException {

servlet.delUser("nameValue8") ;

}

public void testDelAll() throws javax.ejb.EJBException {

servlet.delAll() ;

}

public static void main(String[] theArgs)

{

junit.textui.TestRunner.main(new String[]{

ManaServletTest.class.getName()});

}

public static Test suite()

{

return new TestSuite(ManaServletTest.class);

}

}

public class ManaServletTest extends ServletTestCase 我们要测试的是一个servlet,所以我们继承ServletTestCase,如果你测试jsp的话,就继承JspTestCase.

public ManaServletTest(String theName) {

super(theName);

}

和junit一下,ServletTestCase不允许使用默认的构造函数,所以必须使用一个带参数的构造函数,并且调用 父类的构造函数。

public void setUp(){

try {

servlet.init() ;

}

catch (ServletException ex) {

ex.printStackTrace() ;

this.fail() ;

}

}

public void tearDown(){

}

setUp是在测试类运行时候首先被调用的办法,在这里可以进行一些数据初始化之类的工作。在这里我们调用了 servlet.init().

在测试类运行的时候需要显式的调用servlet的init()方法。因为cactus在测试servlet的时候是实例化一个ser vlet的,不会调用inti(),而servlet enginer在调用的时候是会自动调用servlet的init()方法的。tearDown方 法在测试完成的时候运行,进行一些必要的数据处理,比如删除一些测试数据等,这里我们没有做任何工作。

public void beginAddUser(WebRequest theRequest)

{

theRequest.addParameter("name", "nameValue");

theRequest.addParameter("pass","passValue") ;

theRequest.addParameter("tel","telValue") ;

theRequest.addParameter("address","addressValue") ;

theRequest.addParameter("email","emailValue");

}

public void testAddUser() throws javax.ejb.EJBException{

servlet.addUser(request,response) ;

}

在Cactus中,你需要用testXXX来命名你的方法,这样Cactus会自动调用这个方法进行测。而BeingXXX则是在调 用test方法之前调用,也就是说在一个功能测试之前运行。这里我们现在beginAddUser中添加一些必要的参数 。WebRequest是Cactus提供的一个类,它允许你设置一些Http参数,如果你使用了 theRequest.addParameter("name","nameValue"),那么在servlet中你就可以用request.getParameter("name") 来取得name的值。当然还可以设置Cookie,Http Head参数。在testAddUser()方法中我们测试addUser方法,如 果测试有异常,则会产生EJBException,得到一个测试失败。

public void testFindByName() throws javax.ejb.EJBException {

User u=servlet.findByName("nameValue") ;

UserInfo ui=u.getUserInfo() ;

this.assertEquals("email",ui.getEmail()) ;

this.assertEquals("tel",ui.getTel()) ;

this.assertEquals("nameValue",u.getName()) ;

this.assertEquals("passValue",u.getPassword()) ;

}

这个测试是测试根据用户名查找用户,之后你可以用assertEquals方法来测试返回的值是否正确。

public static void main(String[] theArgs)

{

junit.textui.TestRunner.main(new String[]{

ManaServletTest.class.getName()});

}

这里我们使用textui来运行我们的测试类,提供文本的测试信息,还有一个Swing的测试方法,一共一个界面, 但是没有什么太大的意义。

到此我们介绍了所有的主要方法。最后我们谈谈如何运行这个测试。

首先下载Cactus。

把lib/下的jar文件加入到 web app的lib下。以及你客户端的classpath中,这是最保险的,虽然不是所有 的jar都用的着。

设置你的Cactus.找到cactus.properties 文件,把它加入到客户端的classpath中。

修改cactus.properties 文件,把http://localhost:8080/test 改成你相应的设置,test是你web应用的 名称。其他设置可以不变。

修改服务器端web应用的配置,在web.xml中加入: <?xml version="1.0" encoding="ISO-8859-1"?>

<filter>

<filter-name>FilterRedirector</filter-name>

<filter-class>org.apache.cactus.server.FilterTestRedirector</filter-class>

</filter>

<filter-mapping>

<filter-name>FilterRedirector</filter-name>

<url-pattern>/FilterRedirector</url-pattern>

</filter-mapping>

<servlet>

<servlet-name>ServletRedirector</servlet-name>

<servlet-class>org.apache.cactus.server.ServletTestRedirector</servlet-class>

</servlet>

<servlet>

<servlet-name>JspRedirector</servlet-name>

<jsp-file>/jspRedirector.jsp</jsp-file>

</servlet>

<servlet-mapping>

<servlet-name>ServletRedirector</servlet-name>

<url-pattern>/ServletRedirector</url-pattern>

</servlet-mapping>

<servlet-mapping>

<servlet-name>JspRedirector</servlet-name>

<url-pattern>/JspRedirector</url-pattern>

</servlet-mapping>

编译ejb和servlet,把EJB文件的jar,和servlet的war文件打包成 ear文件。

发布你的ear文件到web application.

运行本地的测试文件ManaServletTest.class

哈哈~~,终于完成了所有的工作,我们可以看看运行结果,"哦,不",居然出现了一个Error,那就是你的程序出现了问题,仔细看看吧,测试是不会骗你的 :) 。 以上代码在 win2000+JBOSS3.0+MySql MAX 3.24+Cactus1.3上运行成功。

关于作者

韩伟,任北京某公司系统分析员,主要从事j2ee发面的开发,对设计模式,Java,软件工程很感兴趣。您可以通过email:java_cn@21cn.com跟他取得联系。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有