怎么样处理异常?

  处理异常有两种基本的方式:在程序内部捕获它并处理

    try{}

   catch(){}

   或者:在方法的异常规范中声明,告诉上一层的程序,本代码会掷出异常,请处理

  throws Exception{}

   但是,怎么样选择这两种方法呢?

  我看了一下thinking in java 3rd

  里面有一段关于处理方法的选择的话附于后:

  我觉得可以理解下面一些原则:

  1、目的:把处理异常的部分和功能部分分开,使系统易于理解和维护;

  2、原则:你如果不知道怎么处理一个异常就不要捕获它(而把它交给上级处理);

  3、但是具体的处理方式仍是灵活多变的,In this section we’ll look at some of the issues and complications arising from checked exceptions, and options that you have when dealing with them.

所以,我现在只有在利用原则2的情况下使代码尽可能的简单。

  4、最后那段话不大明白,好像是说从原来C风格的异常处理转过来的人会感到有很大的利益的改变,但是作者感到当它使用起来不大方便的时候又有点迷惑了。最后写了一句什么:“所以的模型都是错的,一些是有用的”。是什么意思?世上没有十全十美的方法吗?

Alternative approaches

An exception-handling system is a trap door that allows your program to abandon execution of the normal sequence of statements. The trap door is used when an “exceptional condition” occurs, such that normal execution is no longer possible or desirable. Exceptions represent conditions that the current method is unable to handle. The reason exception handling systems were developed is because the approach of dealing with each possible error condition produced by each function call was too onerous, and programmers simply weren’t doing it. As a result, they were ignoring the errors. It’s worth observing that the issue of programmer convenience in handling errors was a prime motivation for exceptions in the first place. Feedback

One of the important guidelines in exception handling is “don’t catch an exception unless you know what to do with it.” In fact, one of the important goals of exception handling is to move the error-handling code away from the point where the errors occur. This allows you to focus on what you want to accomplish in one section of your code, and how you’re going to deal with problems in a distinct separate section of your code. As a result, your mainline code is not cluttered with error-handling logic, and it’s much easier to understand and maintain. Feedback

Checked exceptions complicate this scenario a bit, because they force you to add catch clauses in places where you may not be ready to handle an error. This results in the “harmful if swallowed” problem:

try {

  // ... to do something useful

} catch(ObligatoryException e) {} // Gulp!

Programmers (myself included, in the first edition of this book) would just do the simplest thing, and swallow the exception—often unintentionally, but once you do it, the compiler has been satisfied, so unless you remember to revisit and correct the code, the exception will be lost. The exception happens, but it vanishes completely when swallowed. Because the compiler forces you to write code right away to handle the exception, this seems like the easiest solution even though it’s probably the worst thing you can do. Feedback

Horrified upon realizing that I had done this, in the second edition I “fixed” the problem by printing the stack trace inside the handler (as is still seen—appropriately—in a number of examples in this chapter). While this is useful to trace the behavior of exceptions, it still indicates that you don’t really know what to do with the exception at that point in your code. In this section we’ll look at some of the issues and complications arising from checked exceptions, and options that you have when dealing with them. Feedback

This topic seems simple. But it is not only complicated, it is also an issue of some volatility. There are people who are staunchly rooted on either side of the fence and who feel that the correct answer (theirs) is blatantly obvious. I believe the reason for one of these positions is the distinct benefit seen in going from a poorly-typed language like pre-ANSI C to a strong, statically-typed language (that is, checked at compile-time) like C++ or Java. When you make that transition (as I did), the benefits are so dramatic that it can seem like strong static type checking is always the best answer to most problems. My hope is to relate a little bit of my own evolution, that has brought the absolute value of strong static type checking into question; clearly, it’s very helpful much of the time, but there’s a fuzzy line we cross when it begins to get in the way and become a hindrance (one of my favorite quotes is: “All models are wrong. Some are useful.”). Feedback

(转)[提问] 这样的需求测试用例该怎么设计?(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"参数就不会检出无用的空文件夹了。