(转)[提问] 这样的需求测试用例该怎么设计?(junit答案)

转自:http://www.cntesting.com/bbs/read.php?tid=623&fpage=1

[提问] 这样的需求测试用例该怎么设计?

心力背单词 [traffic /'træfik/ n. 交通(量) ]

到某论坛上逛了一圈,看到了这个提问正好是我的本行,所以特别拿出来秀以下,如果这个朋友到了我们这里可以直接问我。

原贴:

本地写卡功能:

界面:

号码、产品、副号、空SIM卡

号码和空卡为可输入框

1、号码不能是一卡双号的副号,可以是:全球通普通号码,全球通一卡双号主号(若有副号,直接把副号赋给副号输入框处)、神州行、动感地带

2、号码状态必须是正使用状态

3、SIM卡状态是可用状态

4、动感地带号码只能用“28动感地带空白SIM卡”,神州行只能用“29 神州行空白SIM卡”,全球通用“26全球通空白SIM卡”和“27 一卡双号空白SIM卡”;如果输入该号码有副号则只允许写“27 一卡双号空白SIM卡”;

符合1、2、3、4 写卡成功

若号码状态不对, 提示请用正使用的号码

若卡状态不对,提示请用可用状态的卡

若不符合1,提示副号不能写卡

若不符合4,提示卡类型不正确

 

 

测试是非常古老的传统行业,据说地球起源来自于一场非常糟糕的实验。根据我最新考证,上帝创造的亚当夏娃就没有经过很好的测试,不然怎么会因为一个APPLE_BUG就导致了整个世界的崩溃?! 

[楼 主] | Posted:2005-11-03 22:53|  

 

 

smile_xunn

 

 

级别: 测试新手

精华: 0

发帖: 2

测试威望: 2 点

测试币: 6 CSB

测试贡献值: 0 点

在线时间:5(小时)

注册时间:2005-11-08

最后登陆:2005-12-12       

--------------------------------------------------------------------------------

心力背单词 [sail /seil/ n. 帆,航行;vi. 航行,启航,翱游,飘;vt. 航行,飘过 ]

准备一些定义,如下:

全球通普通号码 commonCode

全球通一卡双号主号 doubleCode

神州行 allGo

动感地带 dyArea

号码状态 codeState

SIM卡状态 simState

28动感地带空白SIM卡 dyArea28

29 神州行空白SIM卡 allGo29

26 全球通空白SIM卡 doubleCode26

27 一卡双号空白SIM卡(无副号) doubleCode27

27 一卡双号空白SIM卡(有副号) doubleCode27Fu

测试java伪代码如下:

/**

* 定义一个Product Bean,由它来定义卡的类型,如下:

* 28动感地带空白SIM卡 dyArea28

* 29 神州行空白SIM卡 allGo29

* 26 全球通空白SIM卡 doubleCode26

* 27 一卡双号空白SIM卡(无副号) doubleCode27

* 27 一卡双号空白SIM卡(有副号) doubleCode27Fu

*/

public class Product{

  private String _productId = "commonCode";//产品编码,默认为全球通编码

  private String _productName = "全球通普通号码";//产品名称,默认为全球通描述

  public Product(String productId,String productName){

        this._productId = productId;

        this._productName = productName;

  }

  public Product(){

  }

 

}

/**

* 定义一个Card JavaBean.

*/

public class Card{

  private String _startCode = null;//号码

  private Product _product = null;//产品

  private String _endCode = null;//副号

  private boolean _isState = false;//卡状态

  public Card(String startCode ,Product product,String endCode,boolean isState ){

      this._startCode = startCode;

      this._product = product;

      this._endCode = endCode;

      this._isState = isState;

  }

  public void setStartCode(String startCode){

      this._startCode = startCode;

  }

  public String getStartCode(){

      return _startCode ;

  }

 

  public void setEndCode(String endCode){

      this._endCode = endCode;

  }

  public String getEndCode(){

      return _endCode;

  }

  public void setProduct(Product product){

    this. _product = product;

  }

  public Product getProduct(){

    return _product;

  }

  public void setIsState(boolean isState){

    this._isState = isState;

  }

  public boolean getIsState(){

    return _isState;

  }

  /* *

  * 对_startCode,_endCode进行代码检查,

  */

  public boolean isRightCode(){

    return false;//没有作代码实现,返回值为false;

  }

  /**

  * 得到代码范围,通过判断主号和辅号,判断该号码属于哪种卡,如“28动感地带    

  * 空白SIM卡”

  */

  pubic String getCodeType(){

    //未作实现代码返回值为空

    return null;

  }

}

/**

* 使用继承junit TestCase 的 CardTest类进行测试

*/

public Class CardTest extends TestCase{

  public void testWriteCard(Card card){

    //如果号码状态不对,提示请用正使用的号码

    assertTrue(card.getIsState(),"请用正使用的号码");

    //若卡状态不对,提示请用可用状态的卡

    assertTrue(card.isRightCode(),"请用可用状态的卡");

    // 如果输入该号码有副号则只允许写“27 一卡双号空白SIM卡”;

    if(card.getEndCode()!=null &&!card.getEndCode().trim().equals("")){

    card.getCodeType().equals("27 一卡双号空白SIM卡");

    }

    //1、号码不能是一卡双号的副号,可以是:全球通普通号码,全球通一卡双号主号     //(若有副号,直接把副号赋给副号输入框处)、神州行、动感地带

    String productName = card.getProduct().getProductName().;

   

    if(productName .equals("全球通普通号码")){

        //全球通用“26全球通空白SIM卡”和“27 一卡双号空白SIM卡”        

      if(!(card.getCodeType().equals("26全球通空白SIM卡")||

        card.getCodeType().equals("27 一卡双号空白SIM卡"))){

            assetFalse(true,"卡类型不正确");

      }

    } else if(productName.equals("全球通一卡双号主号")){

        //ok;

    }else if(prodcutName.equals("神州行")){

        //神州行只能用“29 神州行空SIM卡”          

        if(!card.getCodeType().equals("29 神州行空白SIM卡")){

            assetFalse(true,"卡类型不正确");

        }

    }else if(prodcutName.equals("动感地带")){

        //动感地带号码只能用“28动感地带空白SIM卡”

      if(!card.getCodeType().equals("28动感地带空白SIM卡")){

            assetFalse(true,"卡类型不正确");

      }

             

    }else{

        assertTrue(false,"副号不能写卡");

    }

    asserTrue(true,"写卡成功");

   

}

 

 

[转帖] 利用StrutsTestCase测试Struts应用程序

转自:http://www.cntesting.com/bbs/read.php?tid=1239

--------------------------------------------------------------------------------

[转帖] 利用StrutsTestCase测试Struts应用程序

心力背单词 [partly /'pa:tli/ ad. 部分地,在一定程度上 ]

作者:叶枫(http://blog.matrix.org.cn/page/叶枫)

关键字:Struts StrutsTestCase

一、Struts测试概述

 

  一个具有良好系统架构的J2EE应用程序至少有三层组成,即表现层,商业层和系统

集成层(包括数据存取以及和其他系统集成),目前,Struts是应用比较广泛,实现MVC2模式应用于表现层的一种技术. 在这里面,Struts Action主要用来完成一些简单的数据校验,转换,以及流程转发控制(注意:这里流程不是业务规则). 因此在对整个应用程序进行测试时,我们同时也要测试Struts Action.

  但是,测试Struts Action相对测试简单的JavaBean是比较困难,因为Struts是运行在Web服务器中, 因此要测试Struts Action就必须发布应用程序然后才能测试. 我们想象一下,对于一个拥有上千个JSP page和数百甚至数千Java Classes的大规模应用程序,要把他们发布到诸如Weblogic之类的应用服务器再测试,需要多少的时间和硬件资源? 所以这种模式的测试是非常费时费力的.

  所以,如果有一种办法能够不用发布应用程序,不需要Web服务器就能象测试普通Java Class一样测试Struts Action,那就能极大地加强Struts的可测试性能,使应用程序测试更为容易,简单快速. 现在这个工具来了,这就是StrutsTestCase.

二、StrutsTestCase 概述

  StrutsTestCase 是一个功能强大且容易使用的Struts Action开源测试工具,

它本身就是在大名鼎鼎的JUnit基础上发展起来的。因此通过和JUnit结合

使用能极大加强应用程序的测试并加快应用程序的开发.

 

  StrutsTestCase提供了两者测试方式,模仿方式和容器测试方式. 所谓模仿方式就是有StrutsTestCase本身来模拟Web服务器. 而容器测试方式则需要Web服务器. 本文要讨论的是前者,原因很简单,不需要Web服务器就能象测试普通的Java Class一样测试Struts Action.

三、准备StrutsTestCase和Struts Action/ActionForm/Config

  StrutsTestCase是一个开源工具,可以到http://strutstestcase.sourceforge.net下载. 目前最新版本是2.1.3,

如果你使用Servlet2.3就下载StrutsTestCase213-2.3.jar,使用Servlet2.4的就下载StrutsTestCase213-2.4.jar.

另外StrutsTestCase本身就是从JUnit继承的,所以你还需要下载JUnit3.8.1.

  在本文中,我们用一个简单的例子来做测试. 假设我们有一张表Hotline(country varchar2(50),pno varchar2(50)),

我们要做的是根据输入条件从这张表检索相应的记录.检索条件是country.

Value Object: 

package sample;            public class HotlineDTO implements Serializable{        private String country = "";       private String pno = "";                /**         * Method HotlineActionForm         *         *         */        public HotlineDTO () {             super();      }                public void setCountry(String country) {                this.country = country;         }        public void setPno(String pno) {                this.pno = pno;         }        public String getCountry() {                return (this.country);         }        public String getPno() {                return (this.pno);         }              }

ActionForm:

     

package sample;      import org.apache.struts.action.ActionForm;      public class HotlineActionForm extends ActionForm{        private String country = "";        private String pno = "";                /**         * Method HotlineActionForm         *         *         */        public HotlineActionForm() {                super();        }                public void setCountry(String country) {                this.country = country;         }        public void setPno(String pno) {                this.pno = pno;         }        public String getCountry() {                return (this.country);         }        public String getPno() {                return (this.pno);         }              } 

Action Class:

     public class SearchHotlineAction extends Action {     public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request,      HttpServletResponse response) throws Exception {        String target = "";        try{         //调用HotlineDAO检索hotline         String country=((HotlineActionForm)form).getCountry();         List hotlineList = HotlineDAO.getHotlineList(country);         if(hotlineList!=null && hotlineList.size()>0){            request.setAttribute("hotlineList",hotlineList);            target = "hotlineList";         }else{            target = "notfound";         }        }catch(Exception ex){           ....        }                             }

Struts Config:

 

<struts-config>      <form-beans>     <form-bean name="hotlineActionForm" type="sample.HotlineActionForm" />       .......   </form-beans>  <action-mappings>     <action path="/SearchHotline"           name="hotlineActionForm"           type="sample.SearchHotlineAction "                     scope="request"                                                      validate="false">       <forward name="hotlineList" path="/hotlineList.jsp"/>              <forward name="notfound" path="/searchHotline.jsp"/>   </action>    .....  <action-mappings>   ........ <struts-config>

四、初试StrutsTestCase

    当采用模拟方式时,所有的StrutsTestCase测试Class都是从MockStrutsTestCase继承下来的.

    下面我们就创建一个最简单的测试Class.

   

public class SearchHotlineAction extends MockStrutsTestCase {     public void setUp()throws Exception{     }     public void tearDown()throws Exception{     }    public void testSearchHotline() throws Exception{    setRequestPathInfo("/SearchHotline.do");    addRequestParameter("country", "CN");    actionPerform();    }    }

   上面的Class相信用过JUnit的朋友都很熟悉.

    好了,一个简单的测试例子就完成了,如果你用的是Eclipse就选择Run-Run...-JUnit-New就可以直接运行.不需要发布你的程序,不需要任何的Web服务器支持,就可以测试Struts Action,这就是StrutsTestCase带来的好处.下面简单地介绍一下它是怎么工作的.

    在上面的例子中,我们调用setRequestPathInfo()告诉StrutsTestCase我们要模拟JSP调用SearchHotline.do这个Action,并且调用addRequestParameter()增加了一个参数country.最后调用actionPerform()运行.

看到这里,大家发现一个问题没有? 在上面Action的源代码里我们是通过

String country=((HotlineActionForm)form).getCountry();

也就是ActionForm来取得输入的参数值,可我们在testSearchHotline()方法里并没有设置ActionForm?

那么它是怎么出来的呢? 其实大家如果熟悉Struts的运行流程的话就知道,JSP接受用户的输入并发请求时

都是类似这样的http://hostname/servletName?param1=value1¶m2=value2. 只是Struts接受到这些

参数后再根据Struts Config里的Action和ActionForm的映射把他们转为ActionForm后传给Action的.

   在上面的例子,我们只是简单地运行了Action,那么Action是否正确执行以及返回的结果是不是我们想要的呢?

我们继续完善一下testSearchHotline()这个Method.

public void testSearchHotline() throws Exception{

    setRequestPathInfo("/SearchHotline.do");

    addRequestParameter("country", "CN");

    actionPerform();

    verifyNoActionErrors();

    verifyForward("hotlineList");

    assertNotNull(request.getAttribute("hotlineList"));

    List hotlineList = (List) request.getAttribute("hotlineList");

    for (Iterator it = hotlineList.iterator();it.hasNext();){

     ....

    }

    }

我们在actionPerform()后增加了几行语句来断定Struts Action是否正确执行.

   verifyNoActionErrors() -- 判断Action里没有任何的Action;

   verifyForward("hotlineList") -- 判断Action确实转发到hotlineList;     

   assertNotNull(request.getAttribute("hotlineList")) -- 判断Action确实返回了hotlineList并且不为空

到这里,我们已经基本上讨论完了StrutsTestCase的核心部分. 从头到尾,我们没有发布应用程序,也不需要Web服务器,对我们来讲,Struts Action就象普通的Java Class一样容易调试测试.这就是StrutsTestCase给我们带来的方便.

五、深入StrutsTestCase

  除了以上我们用到的几个断定和校验方法外,StrutsTestCase还提供了其他几个方法便于我们测试Struts Action. 下面我一一讲述,具体的大家可以参考文档.

verifyActionErrors/Messages --  校验ActionActionServlet controller 是否发送了ActionError或ActionMessage.   参数为ActionError/Message Key

verifyNoActionErrors/Messages --校验ActionActionServlet controller 没有发送ActionError或ActionMessage

VerifyForward -- 校验Action是否正确转发到指定的ActionForward.

VerifyForwardPath -- 校验Action是否正确转发到指定的URL

verifyInputForward -- 校验Action是否转发到Action Mapping里的input属性

verifyTilesForward/verifyInputTilesForward--和以上类似,应用程序使用到tiles时用的

六、关于Web.xml和Struts-Config.xml

  缺省情况下,StrutsTestCase认为你的Web.xml和struts-config.xml的路径分别是:

  /WEB-INF/web.xml和/WEB-INF/struts-config.xml

  1. 假如你的web.xml/struts-config.xml的路径是

  d:/app/web/WEB-INF/web.xml(struts-config.xml)的话,就需要把d:/app/web加到classpath.

 

  2. 假如你的struts config是strust-config-module.xml,

  那么必须调用setConfigFile()设置你的struts config文件

 

七、结束语

  J2EE应用程序的测试在开发过程中占有相当重要的位置,利用StrutsTestCase能极大方便你测试基于Struts的应用程序.

关于作者:

叶枫:热爱Java和Oracle. 在软件开发有近10年, 目前在国外一家美国大公司担任SA, 负责技术研究。

网站访问中断3天

  由于空间提供商ip变化的缘故,网站中断访问3天,今天早上由他们把问题解决了。

  但是,我修改了域名管理中的密码后就一直不能进入域名管理,正在咨询提供商:www.java-cn.com

  我觉得他们以往的服务还是基本上可以的。

学习日记cvs库改变目录结构后eclipse2.1设置要点

  在网友ppig的建议下,我们把cvs库old目录下的目录结构作了一番调整。这样,使整个结构更合理,但是,在开发环境的设置下需要作一定的设置。

  这里以eclipse2.1+easyStruts0.6.4+tomcat5.0为例说明一下比较关键的地方:

  1、把源文件目录和class文件的输出目录作相应的改变;

  2、把编译库的目录设置为改变后的目录;

  3、把/web目录设为tomcat的工程根目录;

  4、在easyStruts设置<basePackage>/web</basePackage>;

  我在这个过程中有一个疑问,当新建一个工程并把用wincvs检出的工程文件导入已经存在的工程,cvs路径能够使用,但用eclipse的sychronize with Repository,显示所有的本地文件均以更新。但是查看文件内容,又没有更新的地方。可能是cvs比较更新的条件我不懂吧。

  由于必须存在.easystrutsplugin,.project,.tomcatplugin,eclipse2.1才能以导入存在的工程的方式,只有这样,用eclipse的sychronize with Repository才不会把没有更新的文件显示为更新,所以,我又把这3个文件从删除状态中恢复过来。真搞不懂是为什么。

  另外,在tomcat设置页上,要设置:subdirctory to set as web application root(optional)=/web;

在easyStruts的设置页上,web context也必须是/web,即对应上面的这1句:<basePackage>/web</basePackage>;

否则,不管是启动或关闭eclipse等操作,就会报:unable to load modules的错误。

现在写日记不大方便,应该使这个主要的功能变方便

  例如:在菜单栏中加入写作日记的项目,用户写日记时可以直接在一个下拉列表中选择日记所属的目标;

  在目标的内容显示页和目标的日记列表上部均加入写日记的链接,用户在这个目标下提交了日记即表示加入了这个目标。

  另外,现在是提倡个性的时代,有必要实现BLOG的界面形式,但核心思想-以目标为导向,大家共享目标和实现目标的过程这一核心思想不能变,还应该进一步的发展和发挥这个思想。

改变CVS库的目录结构

  根据网友ppig的建议,改变了CVS库old目录下面现在的工程目录结构,改变后的结构更加合理和方便大家的使用。

  但是,如果在网页上直接查看目录结构还是显得太乱,因为由于cvs固有的特点,在客户端不能移走目录。但是,用cvs客户程序(如在eclipse2.1中)检下来的程序的目录中就不会包含那些空的无用的文件了。命令行的cvs要带一个"-P"参数就不会检出无用的空文件夹了。

(转载来自umlchina讨论组)业务对象模型(领域模型)的作用?

 UMLChina@yahoogroups.com

From: "Stephen Suen (SUNRUJUN)" <stephen.suen@gmail.com>  Add to Address Book  Add Mobile Alert 

Date: Mon, 5 Dec 2005 18:42:44 +0800

Subject: Re: 答复: 回复: [UMLChina] 业务对象模型(领域模型)的作用? 请教专家

    

业务建模的作用是为企业现有业务建立模型,需要的话,在此基础之上进行业务重组或者优化。业务模型将用作后续软件过程的输入。

 

实践中,通常我们会跳过业务建模的过程。当然,前提是我们认为业务建模是没有必要的。对于某些应用所面对的业务,其流程和涉及的实体可能是极其复杂的,软件工程人员无法轻易了解业务。此时,业务建模过程将有效地帮助软件工程人员理解业务(尤其是借助UML等图形工具的情况下),并使这些理解得到记录和整理。同样借助图形工具,比如时序图,状态图等,可以分析业务,需要的话,可以进行重组和优化。

 

对于业务建模,常见的两个问题是该做的时候没有作和不必要的时候却做了。

 

面对复杂业务,缺失业务建模过程使得软件工程人员根本不可能真正的理解业务,更加无法真正的理解用户需求,而是仅仅依赖用户的口述等获得大量似是而非的理解,最终导致大量的变更,甚至更严重的问题。如果进行业务建模,基于模型,你甚至会发现用户没有告诉过你的事物。更好的理解,意味着更好的沟通,进而更完善的需求。

 

另一个问题,是僵化的套用软件工程理论,在没有必要的情况下进行业务建模。对于一些简单业务,在全体人员可以轻易的理解业务的情况下,完全没有必要进行业务建模。有些组织为了诸如所谓"规范"等等理由而不是工程理由而要求这样的过程,反而会带来问题。因为业务建模和系统建模的过程具有传承关系,二者之间的一致性需要付出相当的代价。如果业务或者你的经验允许你直接进行系统建模,完全没有问题。当然,如果业务建模的文档可以卖出价钱的话,业务建模有相应的经济回报也未尝不可。

 

On 12/5/05, 赵鹏 <zhaopeng@webservice.com.cn> wrote:

是否可以认为"业务建模",就是"整合业务""优化流程"的过程?!

 

--------------------------------------------------------------------------------

发件人: UMLChina@yahoogroups.com [mailto: UMLChina@yahoogroups.com] 代表 孙向晖

发送时间: 2005年12月5日 14:19

收件人: UMLChina@yahoogroups.com

主题: 回复: [UMLChina] 业务对象模型(领域模型)的作用? 请教专家

 

首先,业务建模并不是开发过程中必需的。

其次,业务建模的作用还是很大的,而现实操作过程中,我们(开发商)往往会忽略业务建模。

业务建模其实分为两个部分来看。一个部分是对as-is建模。另一部分是对to-be建模。as-is,是对企业或者机构等业务建模范围的业务现状建模,以找出其业务过程中实际存在的问题。注意:很多问题,是IT所解决不了的。我们的售前经常跟客户说,只要你能想到的,我们就能做出来。这本身一个很大的问题。企业运营过程中的很多问题,IT都解决不了,或者靠IT来解决,既费工又费力,IT之外,还有更多的更优的方案。所以,在这个方面,IT人士可以做的就是,圈定哪些问题需要由IT来解决,而且必须靠IT来解决的有哪些。

第2个部分,也就是to-be建模。是对企业将来的建模。当我们对企业的业务运营问题给出一个比较好的解决方案后,企业会是一个什么样的运行状况呢?企业不知道,我们也不知道,最好的办法,就是对to-be进行建模。企业应该按照最新的业务模式进行哪方面的业务重组呢?企业是否能够接受这样的业务模式呢?毕竟,业务重组的过程中会牵扯到方方面面人的利益,重组的结果有可能会失败。IT人士也应该把此列入风险中。

 

业务建模的好处:圈定系统边界,理解业务核心,有效掌控风险。

在业务建模的过程中,出来的工具可以做为系统需求(用例)的输入。它们之间有很好的映射关系。但是,这跟是否使用requisitepro工具无关。你甚至可以简单的excel建立自己的跟踪矩阵。。

rockhai2005 < rockhai2005@yahoo.com.cn> 写道:

一个项目,采用ROSE的RUP模版建模。已经确定用到业务用例,进而用到业务对

象模型。现在有一些疑惑,不太明了:业务对象模型到底有什么作用?

我已经了解到的作用如下:

** 对执行业务功能的对象和这些对象之间的关系进行建模,即进一步(或同

时)解释业务用例。这样做的好处是在机构的层面上,更好地就未来系统完成的功

能与客户和项目组成员(相关项目干系人STAKE HOLDER)沟通;

那么它的其它作用呢?比如

1.它是否对分析模型有指导作用?就象业务用例指导系统用例一样?对应关系

如何?

2.如果1中的答案是肯定的,那么这种对应关系在ROSE中是否也可以靠

RequisitePro 工具来实现映射?

------------------------ Yahoo! Groups Sponsor --------------------~-->

Get Bzzzy! (real tools to help you find a job). Welcome to the Sweet Life.

http://us.click.yahoo.com/KIlPFB/vlQLAA/TtwFAA/saFolB/TM

--------------------------------------------------------------------~->

Yahoo! Groups Links

<*> To visit your group on the web, go to:

http://groups.yahoo.com/group/UMLChina/

<*> To unsubscribe from this group, send an email to:

UMLChina-unsubscribe@yahoogroups.com

<*> Your use of Yahoo! Groups is subject to:

http://docs.yahoo.com/info/terms/