不知道大家有没有对Web页面进行测试的经历?或者正想要对web页面进行测试?为什么我下面这篇文章没什么人回复呢?是因为JSF用到的人少,还是因为我比较超前没几个人想到对JSF页面进行自动测试呢?呵呵
一直以来,我们使用java语言开发的程序主要是web应用程序而非桌面应用,当然java是完全可以用来开发桌面应用程序的,目前已经有了比较成熟的针对java的单元测试工具Junit,但是Junit在web应用开发过程中却很难派上大的用场,比如如何让程序对JSP页面进行自动测试?
我们在太原铁路项目中普遍采用了JSF框架进行前端页面的展现和服务器端业务逻辑的处理,收到了比较好的效果,提高了工作效率,但是我们在程序开发过程中经常重复出现一些解决过的错误,为了解决这些错误又需要重新寻找出现错误的地方,或者因为改动了一个小的地方而导致其他地方出现问题我们却一无所知。最后我们只能通过一遍遍的点击页面重复测试才能重新树立对程序的信心,然而人是有厌倦心理的,对于一遍遍重复的低级劳动很快就会厌倦,尤其是程序员对自己所写的代码很厌倦测试,这样很难保证程序的质量。于是我们想过引入单元测试,重复的东西让计算机去做,然而对JSF页面进行单元测试是比较困难的,因为JSF程序都是运行在容器环境中的,与HTTP请求和相应是紧密关联,如果我们要对ManagedBean进行测试,需要构造上下文环境,这些上下文环境原本是由浏览器和JBoss之类的容器构造的,让我们自己去编写代码构造上下文环境很难也很不现实,对JSF页面的自动测试也是很难想象的,然而有了JSFUnit的参与这一切将变得很简单,JSFUnit就是我下面要介绍的针对JSF的测试工具。
JSFUnit是jboss开源组织的一个开源项目,JSFUnit beta 1版于2007年11月发布,目前国内使用JSFUnit还比较少,相信日后一定会得到广泛的使用。JSFUnit被设计为通过使用简单的API来完成JSF项目的集成测试和单元测试的工具。它完全可以访问managed beans, FacesContext, EL表达式和JSF内部组件树,同时可以访问每次客户端请求后的HTML相应。
当然JSFUnit还有其他一些功能,比如JSF静态分析测试可以测试JSF的配置文件faces-config.xml,帮你尽早发现配置问题。JSFTimer能够进行JSF生命周期每个阶段的性能测试。从此JSF的测试从难以想象到轻松变为现实。目前还只有JSFUnit的官方网站对它的使用方法进行了比较详细的介绍,如有兴趣可以登陆www.jsfunit.org或者http://www.jboss.com/jsfunit/进行查询。下面我将介绍一下我在使用JSFUnit中的一些经验,希望需要使用它的人能够少走弯路。
我先将官网的开始向导展示出来吧。
1) 首先,务必遵循JSFUnit的金科玉律,那就是使用组件的ID。
在一个页面中的每个组件,你可以选择是否为他们提供一个ID。如果你不愿意这么做的话,JSF会自动为你创建一个。然而,你让JSF为你创建的话,那么你在测试时将很难引用这些组件。因此,你至少应该为你想要测试的每个组件指定一个ID。
例如:
<h:inputText value="#{foo.text}" id="input_foo_text"/>
2) 创建一个JSP或Facelets页面
3)
<f:view>
<h:form id="form1">
<h:outputText value="Enter your name:" rendered="#{empty foo.text}" id="prompt"/>
<h:outputText value="Hello #{foo.text}" rendered="#{!empty foo.text}" id="greeting"/>
<h:inputText value="#{foo.text}" id="input_foo_text"/>
<h:message for="input_foo_text" styleClass="errorMessage"/>
<br/>
<h:commandButton value="Submit" action="/index.jsp" id="submit_button"/>
<h:commandButton value="Goodbye" action="/finalgreeting.jsp" id="goodbye_button"/>
</h:form>
</f:view>
4) 使用JSFUnit Façade API创建一个JUnit 测试。
public class JSFUnitTest extends org.apache.cactus.ServletTestCase
{
public static Test suite()
{
return new TestSuite( JSFUnitTest.class );
}
public void testInitialPage() throws IOException, SAXException
{
// Send an HTTP request for the initial page
JSFClientSession client = new JSFClientSession("/index.faces");
// A JSFServerSession gives you access to JSF state
JSFServerSession server = new JSFServerSession(client);
// Test navigation to initial viewID
assertEquals("/index.jsp", server.getCurrentViewID());
// Assert that the prompt component is in the component tree and rendered
UIComponent prompt = server.findComponent("greeting");
assertTrue(prompt.isRendered());
// Test a managed bean
assertEquals("Stan", server.getManagedBeanValue("#{foo.text}"));
}
}
5) 添加如下内容到你的web.xml文件中
<filter>
<filter-name>JSFUnitFilter</filter-name>
<filter-class>org.jboss.jsfunit.framework.JSFUnitFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>JSFUnitFilter</filter-name>
<servlet-name>ServletTestRunner</servlet-name>
</filter-mapping>
<filter-mapping>
<filter-name>JSFUnitFilter</filter-name>
<servlet-name>ServletRedirector</servlet-name>
</filter-mapping>
<servlet>
<servlet-name>ServletRedirector</servlet-name>
<servlet-class>org.apache.cactus.server.ServletTestRedirector</servlet-class>
</servlet>
<servlet>
<servlet-name>ServletTestRunner</servlet-name>
<servlet-class>org.apache.cactus.server.runner.ServletTestRunner</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletRedirector</servlet-name>
<url-pattern>/ServletRedirector</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>ServletTestRunner</servlet-name>
<url-pattern>/ServletTestRunner</url-pattern>
</servlet-mapping>
6) 将下面这些jars包放到你的WEB-INF/lib下面
首先,你将需要JSFUnit.jar。因为JSFUnit使用JUnit,Cactus和HttpUnit 作为基础框架,你将至少需要这些框架的最小jar包。别担心,你不需要用这些独立的包弄脏你的工程。 JSFUnit文档现告诉了你在测试时怎样使用Ant或Maven来仅仅包含这些额外的JAR包。
下面是在你WEB-INF/lib路径下所需的最起码的几个jar包
• jboss-jsfunit-core-1.0-beta-1.jar
• aspectjrt-1.2.1.jar
• cactus-13-1.7.1.jar
• httpunit-1.6.1.jar
• junit-3.8.1.jar
• jtidy-4aug2000r7-dev.jar
7) 将cactus-report.xsl放在你的WAR文件的根路径下。
点击此处获得cactus-report.xsl
8) 部署应用和运行测试
部署你的JSF应用到所选择的应用服务器中。然后,在浏览器地址栏中输入如下URL就能运行测试程序了。
http://localhost:8088/web/ServletTestRunner?suite=com.foo.JSFUnitTest&xsl=cactus-report.xsl
其中ServletTestRunner类将会用JUnit运行测试并且在浏览器中显示结果。完成这些后,浏览器将会有如下输出。
9) 将JSFUnit测试作为你构建的一部分
在你看到怎样通过浏览器运行JSFUnit测试之后,你可能想集成JSFUnit作为你工程的一部分或测试驱动开发过程的一部分。我们有针对Maven和Ant的文档从wiki page链接过来。
因为JSFUnit基础框架是基于Apache Cactus的,你能用任何Cactus支持的方式建立你的测试程序。
我们当前正在为Ant和Maven开发象Cactus一样的工具,他们的被用在JSFUnit上。我们有一个为第一个JSFUnit beta版的Ant任务为和在第二个JSFUnit beta版发布之前准备好一个Maven插件。
(开始向导展示完毕)
最初,我完全按照官方网站上的使用说明,一步步将jsfunit测试程序添加到我的项目中去,然后启动jboss运行测试程序,没想到第一句就执行错误。这句如下:
// 为要测试的页面发送一个HTTP请求
JSFClientSession client = new JSFClientSession("/transformer_manage.faces");
运行后发生了空指针异常。我无从知道这是什么原因,因为对它还一点也不了解。后来我下载了一个简单的JSFUnit测试样例项目,单独运行后可以成功测试。很奇怪为什么在我的项目中却无法运行,是不是因为我的项目需要登陆才能访问页面,那怎样才能让测试代码自己登陆系统呢?这个问题肯定很多人都会遇到。随后经过进一步查找原因,发现当执行这一语句向服务器发送HTTP请求时,如果没有登陆(身份验证),一个已有的过滤器将会阻止这一访问并返回一个错误页面,这样当然就无法初始化这个要测试的页面了。那么怎么才能解决这一问题呢?后来通过访问官方网站很高兴找到了相关的信息,作者给出了如下的解决办法:
1、 构造自动登陆代码
21 private WebConversation login() throws IOException, SAXException{
//创建一个与服务器的会话
22 WebConversation wc = WebConversationFactory.makeWebConversation();
//请求访问登陆页面并获得响应,并把HTTP响应封装为一个对象。
23 WebResponse resp= wc.getResponse( "http://localhost:8088/web/.../login.jsp" );
//查找响应中ID为“loginCheck”的form
24 WebForm form = resp.getFormWithID("loginCheck");
25 form.setParameter("userName", "yd");
26 form.setParameter("passWord", "");
27 resp= form.submit();
28 return wc;
29 }
这一方法能够创建一个与服务器之间的会话(22行),然后创建一个登陆页面的相应对象(23行),设置用户名和密码,然后提交(27行),最后返回这个回话对象。
2、 用上一方法返回的回话对象创建客户端对象,一切成功!
34 public void testInialpage() throws IOException, SAXException {
35 WebConversation wc = login();
//将WC作为参数创建client对象
36 client = new JSFClientSession( wc , /transformer_manage.faces");
37 // A JSFServerSession gives you access to JSF state
38 server = new JSFServerSession(client);
39 // Test navigation to initial viewID
40 assertEquals(transformer_manage.jsp, server.getCurrentViewID());
41 }
40行是断言返回的页面的ID应该为transformer_manage.jsp,如果返回ID正确则测试通过。
JSFUnit是基于JUnit的,测试代码的规则和JUnit一致,凡是测试方法的名称都必须以test开头,JSFUnit在运行时会逐个执行这些测试方法。一般需要在这些测试方法开始执行前构造一些对象供测试方法调用,对象构造语句需写在serup()方法中,最后必须在tearDown()方法中将这些对象的引用置空,确保内存释放。
下面展示一下我工程中的一个测试类的例子。
public class TestParentTable extends ServletTestCase {
private JSFClientSession client;
private JSFServerSession server;
public void setUp() throws IOException, SAXException
{
testInialpage();
}
public static Test suite() {
TestSuite ts=new TestSuite(TestParentTable.class,"单元测试");
return ts;
}
private WebConversation login() throws IOException, SAXException{
……
}
public void testInialpage() throws IOException, SAXException {
login();
……
}
public void testAdd() throws IOException, SAXException {
//初始时,断言transformer对象的currentObject属性为NULL值
assertNull(server.getManagedBeanValue("#{transformer.currentObject}"));
//模拟点击页面中“增加”按钮这一事件
client.clickCommandLink("initAdd");
//断言页面ID应该为updatePage+".jsp",以判断导航是否正确
assertEquals(updatePage+".jsp", server.getCurrentViewID());
//断言transformer对象的currentObject属性为非NULL值
assertNotNull(server.getManagedBeanValue("#{transformer.currentObject}"));
}
public void testAddSave() throws IOException, SAXException {
……
}
public void testUpdate() throws IOException, SAXException {
……
}
public void testDelete() throws IOException, SAXException {
……
}
public void testQuery() throws IOException, SAXException {
……
}
protected void tearDown() throws Exception {
client=null;
server=null;
}
}
运行测试程序后将会以网页的形式展示测试的结果: 【请看附件1】
这里仅仅是给出了一个简单的展示,省略了一些细节,我将会写出更加详细的使用文档。总之,JSFUnit能够完全模拟人点击页面上各按钮或链接等各种操作,然后获得操作结果,以测试程序是否正确。
我们总是在书上或网络上看见对单元测试必要性的宣传,我这里并不想人云亦云,极力鼓吹单元测试的好处,因为我并没有亲身去体验过一个项目完整的写下了单元测试用例所带来的好处。我只是希望在这方面去进行尝试。毕竟用代码去编写单元测试或集成测试是需要花费时间的,本来项目已经很紧了,程序员很可能不愿意去花费另外的时间编写测试代码。但是如果我们只需要花不多的时间就能完成这些代码,并且这些代码能够为我们以后的测试节省更多的时间那样会不会更划算呢?如果利用JSFUnit能够很好的完成这一点的话,我相信编写测试代码是值得的。
当然我们需要对测试粒度的大小有一个比较折中的选择,粒度太大可能得不到比较好的测试效果,粒度太小会导致花费在测试代码的时间比程序本身还要多。我们写测试代码不可能把所有逻辑路径全覆盖一遍,这样做将花费太多的时间,不得不进行一些舍弃,从而也会带来一些问题,导致我们对程序质量过于自信,虽然测试代码全部通过了,但是任然存在一些未知的错误。我已经进行了一些尝试,认为JSF项目针对JSF页面而非直接对ManagedBean进行测试应该比较好,对ManagedBean测试可能需要构造一些环境参数比如ActionEvent,这是比较困难的。如果我们对JSF页面如上面的代码所示可以模仿真实的人工测试的操作序列,这似乎已不属于单元测试了,而是集成测试,但这种测试粒度应该比较合适。当然这不一定就是最好的办法,在这个问题上需要继续讨论,继续进行新的探索。
想一想以后点击一下“测试”按钮,测试程序将把所有页面从头至尾自动测试一遍,将是多么惬意的事情,感谢JSFUnit。大家一起讨论讨论还有什么好的JSF测试工具!

- 大小: 44.5 KB

- 大小: 75.9 KB
分享到:
相关推荐
最后,为了测试和调试JSF应用程序,我们通常会使用如Tomcat、GlassFish这样的Web服务器,并通过浏览器进行交互。理解如何部署和运行JSF项目也是学习过程中不可或缺的一部分。 总的来说,这个"jspADD添加JSF项目实例...
7. 运行和测试:配置Tomcat或其他应用服务器,运行项目并进行测试。 通过这些步骤,你可以在IDEA中成功创建并运行一个JSF项目。理解并熟练运用javax.faces.jar和javax-inject.jar中的组件和服务,对于提升JSF应用的...
测试JSf WEB应用测试性能,容器内测试测试。。
总结来说,JSF项目实例的搭建涉及多个环节,从环境配置到代码编写,再到项目运行,每一步都需要对JSF和MyEclipse有一定的理解。通过这个实例,开发者可以快速掌握JSF的基本操作,为进一步的Web开发打下基础。
### JSF初级项目开发实例知识点解析 #### 一、JSF简介及基本概念 - **JSF (JavaServer Faces)** 是一种基于Java EE标准的Web应用程序框架,它为开发人员提供了一个简单的方式来构建用户界面。JSF的目标是简化Web...
JSF(JavaServer Faces)是Java EE平台的一个组件,用于构建基于组件的用户界面。它提供了开发Java Web应用程序用户界面的标准编程接口,拥有一套丰富可扩展的UI组件库,并采用事件驱动模型,使得Web应用程序的开发...
本项目“JSF框架的demo项目”是一个简易的示例,旨在帮助初学者理解并掌握JSF的基本概念和用法。** 在JSF中,**组件模型**是其核心特性之一。它将用户界面元素(如按钮、文本框等)作为可重用的组件来管理。这些...
在"Jsf 项目源代码"这个压缩包中,我们可以推测这包含了一个基于JSF 2.0版本的项目。JSF 2.0是该框架的一个重要版本,引入了许多增强功能,例如面部刷新(Facelet)、视图状态管理、自定义标签改进以及请求处理的...
Seam 是一个强大的Java EE框架,它主要用于简化JavaServer Faces (JSF)应用程序的开发,同时提供了对EJB 3、CDI(Contexts and Dependency Injection)、Ajax等技术的集成。在JSF项目中配置Seam,可以充分利用其优势...
这个"JSF实践项目(生活吧)"显然是一个基于JSF开发的生活服务类Web应用,旨在提供方便的生活服务功能。 **项目结构**: 在"LifeBar"这个压缩包中,我们可以推测包含以下几个关键部分: 1. **源代码**:通常包括...
Eclipse是Java开发中常用的集成开发环境(IDE),提供了强大的工具支持,包括对JSF项目的创建和管理。 在"jsf 最简单的eclipse工程例子"中,我们将探讨如何在Eclipse中创建和运行一个基础的JSF项目。这个例子可能...
2. 下载并安装集成开发环境(IDE):如Eclipse或NetBeans,它们提供了对JSF的良好支持。 3. 安装JSF库:JSF的实现有多个版本,如Mojarra(官方实现)和MyFaces。你可以通过Maven或直接下载JAR文件添加到项目类路径中...
JSF FacesContext 详解 FacesContext 是 JSF 框架中一个核心组件,它负责管理 JSF 请求的状态信息。在 Faces API 中,FacesContext 和 ExternalContext 是两个经常使用的类,本文将详细介绍 FacesContext 的编程...
在开发过程中,MyEclipse作为一个强大的集成开发环境,提供了对JSF项目的全面支持,包括代码提示、调试和部署等功能。这使得开发者能够高效地构建和测试智力测试系统。 总结来说,"JSF实现的智力测试系统"是一个...
源代码的测试部分可能会包括单元测试和集成测试,确保分页功能在不同情况下都能正常工作,比如空数据集、单页数据、多页数据以及边缘情况的处理。 总的来说,这个源码示例对于学习和理解如何在JSF项目中实现分页...
本项目聚焦于JSF的文件上传功能,特别是针对大文件的上传,允许用户上传最大可达1.99GB的文件。在实际应用中,大文件上传是一个常见的需求,例如用户可能需要上传视频、大型文档或者数据库备份等。然而,由于HTTP...
这个“JSF与Hibernate整合的登陆”项目为初学者提供了一个实践基础Web应用开发的良好起点,涵盖了前端UI设计、后端数据处理以及两者间的整合。通过这个项目,学习者可以深入理解JSF和Hibernate的工作原理,并提升...
**JSF商品管理小项目帮助文档** JSF(JavaServer Faces)是一种用于构建Web应用程序的Java EE框架,它简化了用户界面组件的开发和管理。在这个JSF2商品管理小项目中,我们深入探讨了如何利用JSF的核心特性来创建一...
jsf实例 JSF学习 JSF jar包 JSF jsf实例 JSF学习 JSF jar包 JSFjsf实例 JSF学习 JSF jar包 JSF jsf实例 JSF学习 JSF jar包 JSF
标题:“JSF2项目开发及所需各种标签集合”指的是在使用JavaServer Faces 2(JSF2)技术栈开发Web应用项目时,需要掌握的多种标签的使用方法,这些标签包括JSF标准标签、HTML标签、Facelets标签和RichFaces标签等。...