- 浏览: 45448 次
- 性别:
- 来自: 上海
最新评论
-
xiao-qiang163:
这个是一个典型的 判断中文英文截取字符串的算法, 中文算两个字 ...
java字节截取字符串 -
jiapumin:
学习了,很实用的
测试驱动开发with Junit(三) -
CoderDream:
personalAction.setPersonalServi ...
Struts2 Spring hibernate with JUnit 测试驱动开发(一) -
CoderDream:
非常不错,感谢分享!
Struts2 Spring hibernate with JUnit 测试驱动开发(一) -
zuowangxi:
Very Good!
Study。。。
测试驱动开发With JUnit(一)
第三章:使用mork进行测试开发:
什么是mork?简单地说mork就是模型,模拟我们测试时需要的对象及测试数据。比如,用过Struts的朋友都知道,Struts中的action类要运行必须依靠服务器的支持,只有服务器可以提供HttpServletRequest,HttpServletResponse对象,如果不启动服务器,那么就没有办法对action类进行单元测试(当然了,使用mock测试除外)。对struts的Action进行测试是很困难的。即使当业务逻辑很好的被限定在业务层,Struts action通常还是会包含很重要的数据验证、数据转换和数据流控制代码。不对Struts action 支路进行测试在代码的覆盖率上会有很多的不足。单单依靠启动服务器运行程序来测试action太过于麻烦。如果让action脱离容器,那么测试就变得极为简单。脱离了容器,request与response对象如何获得?这时可以使用mork来模拟request与response对象,这样测试 action类就会变得极为简单。下面就简单的介绍一下如何使用StrutsTestCase来进行action的测试。
StrutsTestCase介绍
StrutsTestCase工程提供了一种在JUnit框架下测试struts action的灵活、便利的方法。你可以通过设置请求参数,检查在Action被调用后的输出请求或Session状态这种方式对Struts Action做白盒测试。StrutsTestCase 提供了用框架模拟web容器的模拟测试方法也提供了真实的web容器(比如:Tomcat)下的测试方法。所有的StrutsTestCase单元测试类都源于模拟测试的 MockStrutsTestCase或容器内测试的CactusStrutsTestCase。
下面的例子就是使用mock测试,因为它需要更少的启动和更快的运行。
要使用StrutsTestCase请在下列地址下载最新的发行包
http://sourceforge.net/project/showfiles.php?group_id=39190
下面就开始我们的action测试之旅。首先先让我们了解一下要实现的程序的功能:在index.jsp中输入班级编号以列表形式在result.jsp页面中显示相关班级学员信息
在result.jsp中点击学员姓名在info.jsp中显示该学生的详细信息。
(注:这里数据库查询使用基本的jdbc实现,我们假设DAO层已经通过测试,因为这不是我们这里关注的重点,数据库使用SqlServer2000,同时假定你已经具备使用eclipse开发struts的相关知识)
在pubs数据库中新建一个student表,在表中插入如下测试数据。
- use pubs
- go
- create table student
- ([id] int primary key identity(1,1),
- stuName varchar(20) not null,
- stuAge int not null,
- stuSex varchar(20)not null,
- stuClass varchar(20) not null
- )
- go
- insert into student values('jack',23,'man','GS2T11')
- insert into student values('mohindar',24,'man','GS2T11')
- insert into student values('tim',21,'man','GS2T11')
- insert into student values('rose',23,'woman','GS2T11')
- insert into student values('sakura',22,'woman','GS2T11')
- insert into student values('dess',23,'man','GS2T12')
- insert into student values('hiruku',24,'man','GS2T12')
- insert into student values('lucy',21,'woman','GS2T12')
- insert into student values('liky',23,'woman','GS2T12')
- insert into student values('desr',22,'woman','GS2T12')
- go
先让我们来看看第一个功能如何实现:
在search.jsp中填入数据,然后将其提交给SearchAction类来处理。SearchAction类调用业务逻辑层查询,将结果保存至 request对象的属性"result"中,并且跳转至info.jsp页面。如果查询不到结果,就构造一个ActionMessage,封装错误信息,并转向到error.jsp页面。
下面的请求URL将会显示调用SearchAction类:
search.do?method=search
具体步骤如下:
步骤1:在eclipse中放入strutstests-2.1.3.jar,junit.jar、commons-collections.jar
步骤2:构造一个名为SearchForm的ActionForm和一个名为SearchAction 的action。SearchForm的属性为:clazzName
步骤3:更改相应的配置文件
- <form-beans>
- <form-bean name="searchForm" type="com.struts.form.SearchForm" />
- form-beans>
- <action-mappings>
- <action attribute="searchForm" input="/search.jsp"
- name="searchForm" parameter="method" path="/search" scope="request"
- type="com.struts.action.SearchAction" validate="false">
- <forward name="error" path="/error.jsp" />
- <forward name="success" path="/result.jsp" />
- action>
- action-mappings>
步骤4:编写测试类
构造一个名为SearchActionTest的类并继承MockStrutsTestCase。在该类中添
加测试方法testSearchSuccess
- import servletunit.struts.MockStrutsTestCase;
- public class SearchActionTest extends MockStrutsTestCase
- {
- public void testSearchSuccess()
- {
- setRequestPathInfo("/search.do"); //1行
- addRequestParameter("method", "search"); //2行
- actionPerform(); //3行
- }
- }
代码解释:
1行:设置请求SearchAction类的请求路径
2行:在请求路径后加上一个请求参数
1行与2行就构成了/search.do?method=search
3行:调用actionPerform()来执行action类
注:以上代码就是对一个测试方法的初始化。可以根据需要自行修改
步骤5:根据struts-config.xml文件完善testSearch方法。先验证可以按照班级名称查询出所需要的数据,主要做以下事情:
a) 初始化提交数据
b) 验证request中"result"属性是否有值
c) 是否返回result.jsp页面
代码如下:
- public class SearchActionTest extends MockStrutsTestCase
- {
- public void testSearchSuccess()
- {
- setRequestPathInfo("/search.do");
- addRequestParameter("method", "search");
- addRequestParameter("clazzName","gs2t11"); //1行
- actionPerform();
- assertNotNull(request.getAttribute("result")); //2行
- verifyForward("success"); //3行
- }
- }
代码解释:
1行:添加提交数据,该数据就相当与从search.jsp提交的数据
2行:查询成功后,将结果放入request中,所以判断result中的"result"属性是否
有值来断定是否将结果成功放入request对象中。
3行:验证查询成功后是否会返回success.jsp页面
运行junit,如果出现以下错误(具体如下图):(请参考附件吧。这里所有的图都省略……)
那么请在src下建立一个名WEB-INF的目录,将WebRoot下的WEB-INF中的web.xml文件与struts-config.xml文件拷贝过去即可。如图:
步骤6:在SearchAction中用最简单的代码先去实现步骤5中的功能
代码如下:
- public class SearchAction extends DispatchAction
- {
- private SearchHandler sh;
- public ActionForward search(ActionMapping mapping,ActionForm
- form, HttpServletRequest request, HttpServletResponse response)
- {
- SearchFormsearchForm = (SearchForm) form;
- //获取表单中输入的班级
- String className = searchForm.getClazzName();
- //查询该班级的信息
- sh = new SearchHandler();
- List list=sh.searchByClassName(className);
- if(list!=null)
- {
- //将班级信息保存至request中,并返回result.jsp
- request.setAttribute("result",list);
- return mapping.findForward("success");
- }
- else
- return null;
- }
- }
注释比较详细,就不再多解释了
运行测试类结果如下(成功部分编写完毕)
步骤7:编写不能成功取出数据的测试。在SearchActionTest类中添加一个名为testSearchFail的方法
代码如下:
- public void testSearchFail()
- {
- setRequestPathInfo("/search.do");
- addRequestParameter("method", "search");
- addRequestParameter("clazzName","gs2txx"); //1行
- actionPerform();
- verifyActionMessages(new String[] {"no.stuclass.found"});//2行
- verifyForward("error"); //3行
- verifyForwardPath("/error.jsp"); //4行
- }
代码解释:
1行:输入一个不存在的班级
2行:验证向ActionMessages中放入的消息文本
3行:验证返回地址
4行:验证页面地址是否与转向的error对应
步骤8:更改SearchAction类,实现步骤7的功能
代码如下:(粗体为增加部分)
- public class SearchAction extends DispatchAction
- {
- private SearchHandler sh;
- public ActionForward search(ActionMapping mapping,ActionForm
- form, HttpServletRequest request, HttpServletResponse response)
- {
- SearchFormsearchForm = (SearchForm) form;
- //获取表单中输入的班级
- String className = searchForm.getClazzName();
- //查询该班级的信息
- sh = new SearchHandler();
- List list=sh.searchByClassName(className);
- if(list!=null)
- {
- //将班级信息保存至request中,并返回result.jsp
- request.setAttribute("result",list);
- return mapping.findForward("success");
- }
- else
- {
- //构造一个ActionMessage保存一条消息
- ActionMessages messages=new ActionMessages();
- messages.add(Globals.MESSAGE_KEY, new ActionMess("no.stuclass.found"));
saveMessages(request,messages); - //返回error.jsp
- return mapping.findForward("error");
- }
- }
- }
运行测试类,正确
至此第一个功能测试开发完毕
接着我们一起来完成第二个功能:
在result.jsp页面中,点击学生的姓名后将其提交给DisplayAction类来处理。DisplayAction类调用业务逻辑层查询,将结果保存至request对象的属性"stu"中,并且跳转至info.jsp页面
下面的请求URL将会显示调用SearchAction类:
display.do?method=display&stuName=jack
具体步骤如下:
步骤1:构造一个名为DisplayForm的ActionForm和一个名为DisplayAction的Action。DisplayForm的属性为stuName
步骤2:修改相应的struts-config.xml
- <form-beans>
- <form-bean name="displayForm" type="com.struts.form.DisplayForm"/>
- form-beans>
- <action-mappings>
- <action attribute="displayForm"
- name="displayForm" parameter="method" path="/display" scope="request"
- type="com.struts.action.DisplayAction" validate="false">
- <forward name="info" path="/info.jsp" />
- action>
- action-mappings>
步骤3、编写DisplayAction的测试类DisplayActionTest,在其中加入一个名为testShowInfo()的方法。该方法完成以下事情:
a) 初始化提交数据
b) 验证request中"stu"属性是否有值
c) 是否返回info.jsp页面
代码如下:
- public class DisplayActioTest extends MockStrutsTestCase
- {
- public void testShowInfo()
- {
- setRequestPathInfo("/display.do");
- addRequestParameter("method","display");
- addRequestParameter("stuName", "jack");
- actionPerform();
- assertNotNull(request.getAttribute("stu"));
- verifyForward("info");
- }
- }
步骤4:更改DisplayAction类,用最简短的代码实现其功能
代码如下:
- public class DisplayAction extends DispatchAction
- {
- private SearchHandler sh;
- public ActionForward display(ActionMapping mapping, ActionForm form,
- HttpServletRequest request, HttpServletResponse response)
- {
- sh=new SearchHandler();
- DisplayForm displayForm = (DisplayForm) form;
- String name=displayForm.getStuName();
- Student stu=sh.displayByName(name);
- request.setAttribute("stu",stu);
- return mapping.findForward("info");
- }
- }
步骤5:运行测试类,结果正确
至此,第二个功能测试开发完毕
经过前面两个功能的测试与运行,两个功能都可以单独测试通过,由于第二个功能是以第一个功能成功查询为前提才能运行,所以再编写一个测试,将两个 action功能整合。这样就可以测试整个功能模块是否正确。在DisplayActioTest中编写一个名为 testSearchAndDisplay()的方法来完成这个测试吧。
代码如下:
- public void testSearchAndDisplay()
- {
- //先调用SearchAction来取得数据
- setRequestPathInfo("/search.do");
- addRequestParameter("method", "search");
- addRequestParameter("clazzName","gs2t11");
- actionPerform();
- List list=(List) request.getAttribute("result");
- Student student=(Student) list.get(0);
- //调用DisplayAction类显示在result.jsp中选择的数据
- setRequestPathInfo("/display.do");
- addRequestParameter("method","display");
- addRequestParameter("stuName", student.getStuName());
- actionPerform();
- assertNotNull(request.getAttribute("stu"));
- verifyForward("info");
- }
运行测试类,测试成功
整个模块到这里全部开发测试完毕,但是还没完,作为测试驱动开发最重要的一环就是重构,这样才能保证你程序的健壮性、可读性、可维护性及优雅性。这里重构主要是针对Action类进行重构,你也可以用同样的方法在编写完测试代码之后对测试代码进行重构。这里主要针对以下几个地方进行重构
1) 抽取Action类中的变量:
SearchAction类中:
- SearchForm searchForm= (SearchForm) form;
- String className = searchForm.getClazzName();
- sh = new SearchHandler();
- List list=sh.searchByClassName(className);
可以用下列代码替换:
- sh = new SearchHandler();
- List list=sh.searchByClassName(((SearchForm) form).getClazzName());
DisplayAction类中:
- DisplayForm displayForm = (DisplayForm) form;
- String name=displayForm.getStuName();
- Student stu=sh.displayByName(name);
- request.setAttribute("stu",stu);
可以用下列代码替换:
- request.setAttribute("stu",sh.displayByName(((DisplayForm)form).getStuName()));
2) 抽取常量:
SearchAction类中:
- request.setAttribute("result",list);
可以用下列代码替换
- private static final String RESULT = "result";
- request.setAttribute(RESULT,list);
SearchAction类中
- request.setAttribute("stu",sh.displayByName(((DisplayForm) form).getStuName()));
可以用下列代码替换
- private static final String STUDENT = "stu";
- request.setAttribute(STUDENT,sh.displayByName(((DisplayForm) form).getStuName()));
构造一个名为BaseAction的类,继承DispatchAction类,并在其中初始化一个SearchHandler对象
- public class BaseAction extends DispatchAction
- {
- protected SearchHandler sh=new SearchHandler();
- }
SearchAction类与DisplayAction类可改为
- public class SearchAction extends BaseAction
- public class DisplayAction extends BaseAction
同时要去掉两个类中的SearchHandler属性
SearchAction类中下列代码可以抽取成方法:
- ActionMessages messages=new ActionMessages();
- messages.add(Globals.MESSAGE_KEY, new ActionMessage("no.stuclass.found"));
- saveMessages(request,messages);
可以用下列代码替换:
- addResultMessage(request,"no.stuclass.found");
- private void addResultMessage(HttpServletRequest request,String message)
- {
- ActionMessages messages=new ActionMessages();
- messages.add(Globals.MESSAGE_KEY, new ActionMessage("no.stuclass.found"));
- saveMessages(request,messages);
- }
由于在别的Action中也要经常生成ActionMessages对象,所以再将该方法 抽取到BaseAction中。
最后BaseAction类代码如下:
- public class BaseAction extends DispatchAction
- {
- protected SearchHandler sh=new SearchHandler();
- protected void addResultMessage(HttpServletRequest request, String message)
- {
- ActionMessages messages=new ActionMessages();
- messages.add(Globals.MESSAGE_KEY, new ActionMessage(message));
- saveMessages(request,messages);
- }
- }
最后代码效果请参考源代码。
4) 重构注意事项:
a) 每次要一点点的重构,万万不要一次重构很多地方。
b) 每重构完一个地方要运行测试类来保证其正确性。
c) 不要怕麻烦。在后期重构的优势就会越来越明显。
到此为止,全部的测试与代码编写已经结束。还等什么,将已经做好的页面套上去吧,感受一下不用启动服务器来开发web应用程序的乐趣吧,感受测试驱动开发给你带来的开发思想的质的飞跃……
- 测试驱动开发With JUnit.rar (2.7 MB)
- 描述: 前三章案例
- 下载次数: 242
- 测试驱动开发With JUnit.rar (297.2 KB)
- 描述: 详细文档。
- 下载次数: 107
相关推荐
总结,测试驱动开发With Junit涉及到的主要知识点包括: - TDD(测试驱动开发)的概念和流程 - JUnit作为Java的单元测试框架,如何创建测试类和测试方法 - 如何使用`assert`方法进行断言,确保代码行为正确 - 创建和...
本文将深入讲解JUnit 4的关键特性和如何进行测试驱动开发。 1. 预备知识 在开始使用JUnit 4进行测试之前,了解一些预备知识是必要的。例如,Java 5引入的可变长参数(Variable-Length Arguments)允许函数接收不定...
《Pragmatic Unit Testing in Java with JUnit》是一本专注于Java单元测试实践的书籍,其配套源代码提供了丰富的示例和实践案例,帮助读者深入理解如何有效地使用JUnit进行单元测试。JUnit是Java领域最广泛使用的...
2. `@RunWith(SpringRunner.class)`:这是一个JUnit runner,它使得Spring TestContext Framework可以驱动测试执行。 3. `@SpringBootTest`:这个注解用于启动一个Spring应用上下文,可以指定配置类、web环境等。 ...
这个"junit4测试源码"可能包含了JUnit4框架的源代码,使得用户能够深入理解其内部工作原理,便于自定义扩展或学习测试驱动开发(TDD)的最佳实践。 首先,JUnit4引入了注解(Annotation)的概念,使得测试类和测试...
10. **TDD(测试驱动开发)**:JUnit也支持采用TDD(Test-Driven Development)模式,即先写测试,再编写能通过测试的代码,这有助于提高代码质量和可维护性。 总之,JUnit作为Java的主流测试工具,其强大功能和...
在实际项目中,应当结合TDD(测试驱动开发)理念,先编写测试再实现功能,确保代码质量从一开始就得到保障。 总之,软件测试是保障软件质量的重要手段,而Junit作为Java的主流单元测试框架,为开发者提供了强大的...
《Pragmatic Unit Testing in Java with JUnit》是一本专注于Java单元测试的指南,它深入讲解了如何有效地利用JUnit框架进行测试驱动开发(TDD)。JUnit是Java领域中最广泛使用的单元测试框架,它为开发者提供了编写...
【标题】"junit4 单元测试源码"涉及的是Java编程中单元测试的重要工具...通过分析和运行这些源码,学习者可以掌握单元测试的基本概念,了解如何编写有效的测试用例,以及如何利用Eclipse的集成环境进行测试驱动开发。
- **Al Koscielny**(软件开发者):“如果在我开始进行测试驱动开发时就有这本书就好了。” - **Andrew Thompson**(顾问,Greenbrier & Russel):“虽然我对测试并不陌生,但我仍然在很多方面感到困惑。我认为这...
Junit单元测试是Java开发中的一个关键组成部分,它允许开发者对代码进行小规模的验证,确保每个函数或方法按照预期工作。本指南将深入探讨Junit的使用,帮助你掌握如何编写、运行和理解单元测试。 一、Junit简介 ...
使用这个工具,开发者可以在Matlab中实现类似Java的测试驱动开发(TDD)或行为驱动开发(BDD)实践,从而提升代码质量和维护性。同时,通过JUnit兼容的XML输出,可以方便地将Matlab项目集成到更广泛的软件开发流程中。
1. **注解驱动(Annotation-Based)**:JUnit 4.5引入了注解来声明测试方法和类,如`@Test`、`@Before`、`@After`等,这使得测试代码更加简洁易读。 2. **参数化测试(Parameterized Tests)**:`@RunWith...