基于
Junit2.0
的
StrutsTestCase
应用
在我的前一篇文档《测试驱动的开发是重要的》中说过我要写一些测试框架应用方面的文档,今天我要实现我的诺言之一,这篇文章是介绍
StrutsTeseCase
的,熟悉并采用
struts
的开发员曾经一定有过这样一个困扰:我的
action
如何进行测试?(不是说要“测试先行”么?),如果没有一个可行的测试框架那我的
struts
环境去哪里模拟(方便的、透明的去模拟)?不要着急,接下来的部分我要向你们介绍这样一种可以满足我们要求的测试框架
:strutstestcae
。
——写在前面
主要内容介绍:
1.
StrutsTeseCase
是什么?
2.
它的“家”在哪里?
3.
如何让它来为我们工作?(伴随说明:我到底该实施“测试先行”?)
4.
兼容
struts1.1
开发员
5.
参考资源
“由于在这里没有牵涉到
Struts
以及
Junit
入门的知识,所以我假定这篇文章的读者都是有
struts
开发经验的开发员并熟悉
Junit
。”
第一部分:
StrutsTestCase
是什么?
StrutsTestCase
是基于
Junit
的一个方便测试
struts
框架的测试框架。它提供模拟对象(
Mock Object
)和
Cactus
两种方式来“真实”的运行
Struts ActionServlet
,它允许你在不启动
servlet
引擎的情况下测试你的
struts
代码。因为
strutstestcase
可以用
ActionServlet
来测试你的代码,所以它不光可以测试你的
action
,同时它也可以测试你的(容器中的?)
mapping,frombeans
以及
forwards
声明。我前面曾提到过它对我们开发员来说是“透明的”,因为象
action,mapping,form beans
以及
forward
等等,我们真的可以象在常规的
XXXAction
中一样在我们的测试代码中随意的使用它们。
在最新的版本中它还提供了对
tiles
和多模块(
struts1.1
中的功能)的测试。
哇,是不是很奇妙,不要着急,我们很快就可以领略到的它的妙处。
第二部分:它的“家”在哪里?
就象许许多多的开源项目一样,
StrutsTestCase
的家也在“
sourceforge.org
”(我们伟大的
sourceforge
就象一个繁忙的峰槽一样
J
),你可以通过
http://sourceforge.net/project/showfiles.php?group_id=39190
来下载它得最新版本。
JavaDoc: http://strutstestcase.sourceforge.net/api/index.html
热点论坛:
http://sourceforge.net/forum/forum.php?forum_id=121751
常见问题:
http://strutstestcase.sourceforge.net/faq.htm
第二部分:如何让它来为我们工作?
“模仿测试(
Mock Testing
)
VS
容器内测试(
In-Container Testing
)”
通常测试服务器端代码有两种比较常用的测试方法:
模仿对象(
mock objects
)它通过假设服务器端容器来达到测试效果;
容器内测试(
in-container testing
)
,
它则是在真实的容器内达到测试效果;
而我们的
StrutsTestCase
则在对你的测试代码最小影响下能分别扮演上边两种角色。因此我们不得不说到它的这两种实现是如何完成的?
StrutsTestCase
提供两种基类(他们分别继承标准的
Junit TestCase
):
MockStrutsTestCase:
通过名字也可以知道他是通过第一中方法在不启动
servlet
的条件下来模仿一些
HttpServlet
实现假设容器环境的。
CactusStrutsTestCase:
它是体现在容器内测试(真实环境测试)的,其通过另外一种测试框架(
Cactus testing framework
:
http://jakarta.apache.org/cactus
)
struts
代码。
Ps:
本文中牵涉的代码都是通过第一中方法(继承
MockStrutsTestCase
)来完成测试的,要想用
CactusStrutsTeseCase
你只要简单的让测试代码继承
CactusStrutsTeseCase
即可。
下面我们着重讲解
MockStrutsTestCase
是为我们工作的?
首先我们先看看一个简单的
LoginAction
的简化代码:
public class LoginAction extends Action {
public ActionForward perform(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
{
String username = ((LoginForm) form).getUsername();
String password = ((LoginForm) form).getPassword();
ActionErrors errors = new ActionErrors();
if ((!username.equals("Jplateau")) || (!password.equals("sandy")))
errors.add("password",new ActionError("error.password.mismatch"));
if (!errors.empty()) {
saveErrors(request,errors);
return mapping.findForward("login");
}
// store authentication info on the session
HttpSession session = request.getSession();
session.setAttribute("authentication", username);
// Forward control to the specified success URI
return mapping.findForward("success");
}
|
上边
LoginAction
完成一个简单的登陆意图,从
client
搜集登陆数据(用户名和密码),然后做一个验证,如果验证有误返回登陆页;如果登陆成功返回成功页(或业务工作平台)并把用户姓名放入
session
。
那我们就从上边这个简单的程序入手:
首先,我们应该创建一个测试用例
TestLoginAction
,其基本架子是这样的:
(请记住此时上边
LoginAction
的代码你还没有写,并且
struts_config.xml
中的关于
LoginAction
的
actionmapping
也是没有的,这些东西我们要经过边测试边写,但一定是先写测试,天啊,什么都还没有我该怎样测试啊,不要急,且看下去,
J
)
public class TestLoginAction extends MockStrutsTestCase {
public void setUp() { super.setUp(); }
public void tearDown() { super.tearDown(); }
public TestLoginAction(String testName) { super(testName); }
public void testSuccessfulLogin() {}
}
|
首先我们头脑总中有这样一个
actionmapping(
注意只是假设的
)
:
<action path=”/longin” type=”Jplateau.strutstestcase.LonginAction”
scope="request"
name="userForm">
<forward name="success" path="/main.jsp"/>
<forward name="login" path="/login.jsp"/>
</action>
|
有了这样一个假设,我们就可以从测试代码入手:
public class TestLoginAction extends MockStrutsTestCase {
public void setUp() {
super.setUp();
//
这里做一些初始化的东西,譬如数据库连接等
}
public void tearDown() {
super.tearDown();
//
这里关闭你在
setup
中开启的资源,如关闭数据库连接等
}
public TestLoginAction(String testName) { super(testName); }
public void testSuccessfulLogin() {
//
选择你要执行哪一个
actionmapping?
这里就用我们刚才做的假设材料
this. setRequestPathInfo("/login");
//
首先要初始化提交数据:用户名、密码
this.addRequestParameter(“usrename”,”Jplateau”);
this.addRequestParameter(“passwd”,”sandy”);
//
注意有了这个之后,你就可以从
formbean
中使用提交以后的用户名和密码数据了,下
//
面我会解释
//
好,初始化数据完成以后开始执行
action
中的
execute(),
很简单,掉用
actionPerform()
this.
ActionPerform();
//
严正返回是否正确?这里就用我们刚才做的假设材料
this verifyForward(“success”);
.
//
下面验证登陆成功以后
session
中是否有用户的名称?
String expect_username_from_session=”Jplateau”;
//
这里需要插写内容,就是
strutstestcase
完全可以在测试代码中使用跟真实
action
//
中一样的环境,譬如可以通过
this.getActionForm()
得到相应的
ActionForm
//
可以通过
this.getRequest()
得到
HttpRequest
//
可以通过
this.getSession()
得到
HttpSession,
如下:
String actual_username_from_session=this.getSession().getAttribute(“authentication”);
this
. assertEquals(“”, expect_username_from_session, actual_username_from_session);
}
public void testFailureLogin(){
//
登陆失败的测试在此就不写了
}
}
|
上边是一个简单的测试代码,好,运行!他此时肯定是通不过的,首先我们的
java
代码还没有写,
struts-config.xml
还没有配,那么,现在你可以现在做这些事情:“用最简单的做法或代码让上边那个测试通过。”
第三部分:兼容
struts1.1
开发员
下面说写和
struts1.1
相关的内容:测试
tiles
和多模块!
测试
tiles
假设我们的
actionmapping
中有这样
forward
到
tiles
的情况,如下:
//
这里有关
struts
中
tiles
的使用不做介绍,请参考相关资料
<forwardname="success" path="/userListLayout"/>
|
同时
tiles_defs.xml
中有相应配置:
//
其中
mainLayout
是我在
tiles
定义的类型框架
<definition name="userListLayout" extends="mainLayout">
<put name="body" value="/main.jsp" />
</definition>
|
那么我们在测试代码中可以如下测试
tiles
//
this. verifyTilesForward(“success”,”userListLayout”);
|
测试多模块:
关于多模块的测试我希望能在下面代码的注释部分给你一个大概的介绍:
public class TestLoginAction extends MockStrutsTestCase {
public TestLoginAction(String testName) { super(testName); }
public void testSuccessfulLogin() {
//
“
mymodule
”为系统中某个单独模块的名称(文件夹的名称)
setConfigFile("mymodule","/WEB-INF/struts-config-mymodule.xml");
//
这个地方和前面单模块的例子有些差别,此处有两个参数,第一个参数是模块的
//
名称,第二个参数的意义和上边相同;
//
和单模块相比,就上边两处区别
this.setRequestPathInfo("/mymodule","/login.do");
this.addRequestParameter("username","Jplateau");
this.addRequestParameter("password","sandy");
this.actionPerform();
this.verifyForward("success");
String expect_username_from_session=”Jplateau”;
String actual_username_from_session=this.getSession().getAttribute(“authentication”);
this
. assertEquals(“”, expect_username_from_session, actual_username_from_session);
}
}
|
参考资源:
1.
http://strutstestcase.sourceforge.net
(本篇文章基本上是沿用该篇文档的思路,英文好的可以阅读这篇文档。)
2.
Kent Beck
《
Test-Driven Development By Example
》
3. 本文首发于本人资料站点:http://plateau.sicool.com/
Jplateau 2003
年
11
月
12
日星期三
写于广州精博