`
jiangduxi
  • 浏览: 453287 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

测试是否抛出正确的异常(Test throwing the right exception)

阅读更多
问题:
    你是否想过异常也要去测试?你想了怎么验证一个方法是否在某种特定的情况下抛出期望的异常,也许你正在找是否要测试,以及有没有简单的测试方法

背景:
    要想知道任何实现这种测试,你需要了解JUnit如何判定一个测试时通过还是失败。如果一个断言失败或者抛出一个异常的时候,测试就会失败,否则测试就通过。换句话说,如果一个测试全部走完,就是说程序从头运行到了尾,而没有从中间跳过,那么它就通过了。知道了这些,就足够你推断出然后写这种测试了:如果该抛出异常的代码段没有抛出异常,那么这个测试就应该失败;测试只能捕捉期望的异常;任何其他的异常都应该由JUnit框架捕捉。

诀窍:
   下面的代码展示了,如何写这种验证是否抛出正确异常的测试示例:
  public void testConstructorDiesWithNull() throws Exception{
    try{
        Fraction oneOverZero = new Fraction(1,0);
        fail("Created fraction 1/0! That's undefined!");
      }
   catch(IllegalArgumentException excepted){
       assertEquals("denominator",excepted.getMessage());
        }
  }

首先分析上面的代码
1. 找到可能抛出异常的代码段,将它放入一个try语句内。
2. 调用了应该抛出异常的方法以后,在try语句内写一个fail()方法来说明:“如果运行到了这里,那么说明期望的异常没有被抛出”。
3. 添加一个catch语句以捕获期望的异常。
4. 在catch语句内,如果需要的话,验证捕获的异常的属性与你期望的相同。
5. 声明该测试方法会抛出异常,这可以让代码适应性更强。有人可能会在测试程序外声明这个方法可抛出其他的异常,这种变化不应该影响你的测试,因此它不应该导致你的测试不能被编译。

讨论:
如果测试的方法抛出其他的异常---------不同于你要捕获的异常-----那么JUnit将报告一个error,而不是failure,因为测试方法将一个异常抛出给JUnit框架。记住这样的error一般是环境或者测试程序自身的错误,而不是产品代码的问题。如果产品代码抛出了一个预期之外的异常,那么一般可能是潜在的问题阻碍了测试的正常运行。

一个更面向对象的解决办法
先看一个匿名内部类
    public void testForException(){
      assertThrows(MyException.class, new ExceptionClosure(){
         public Object execute(Object input) throws Exception{
              return doSomethingThatShouldThrowMyException();
             }
        });
      }
 

虽然有人觉得Java的匿名内部类不太好读,但这个方法的意图再明显不过了:"测试这段代码是否抛出期望的异常"。可以按如下的方式实现assertThrows()方法:
  public static void assertThrows(Class expectedExceptionClass, ExceptionalClosure closure){
    String expectedExceptionClassName = expectedExceptionClass.getName();

 try{
       closure.execute(null);
       fail("Block did not throw an exception of type"+expectedExceptionClassName);
     }
catch(Exception e){
   assertTrue("Caught exception of type <" + e.getClass().getName()
              +">, expected one of type <"
              +expectedExceptionClassName+">",
              expectedExceptionClass.isInstance(e));
}
}

我们捕捉了所有的异常,而不仅是期望的异常,这是因为当编译的时候,我们还不知道代码会抛出什么样的异常。如果这样设置断言,那么错误信息就很重要,因为你取走了错误信息的控制权。另外一个可选的方案是,在assertThrows()方法中添加另外一个参数,用来接收自定义的异常,最后,因为我们必须测试所有的异常,我们必须将捕获的异常是否是期望的异常的实例,这与使用instanceof()方法是一样的。

注意写的断言:
如果你的断言与特定的异常相关,那么你要小心:如果验证异常对象的结构过于紧凑,那么可能导致测试与产品代码耦合得过强。这时候,测试的结果可能有点不太可靠。假设异常信息是给终端用户看,而你要写直接验证该消息的断言。一般来说,你会照着如下的方式编写测试代码:
  public void testNameNoEntered(){
   try{
       log("", "password");
       fail("User logged in without a user name !");
       }
 catch(MissingEntryException expected){
      assertEquals("userName", expected.getEnteryName());
      assertEquals("Please enter a user name and try again",
    expected.getMessage());
  
       }
  }

测试代码看上去很清楚:如果一个用户不输入用户名的情况下登录,那么登录模块就抛出一个MissingEntryException。这个异常包含了登录所缺少的必要项的名称,以及提供给终端用户的信息。这看起来很好,因为这个异常对象包含的信息非常简单,它包含的数据像终端用户读取的信息一样易于理解。虽然catch语句中的第一断言写得不错,但是第二个有点不同的意见,虽然userName是程序的内部名称,并且是行为的一部分,但给终端用户看的信息可以在不影响登录功能的前提下随时改变。换句话说,如果userName改变的话,测试程序就需要随之改变。然而,测试似乎不应该随着终端用户信息的改变而改变,由于测试时现在写的,将来任何属性值的改变,都会要求测试程序随之改变。

这个例子中,我们建议去除第二个断言而仅保留第一个,因为涉及的一般准则是:将给终端用户看的信息与内部对象的行为相分离。你可以经常简单地初始化应该异常对象,然后检查它的toString()以及getMessage()方法的返回值。
分享到:
评论

相关推荐

    aop+exception的测试代码

    4. **编写测试方法**:在测试类中,创建一个会抛出异常的方法,并使用断言确保AOP通知被正确执行。 总结一下,"aop+exception"的测试代码主要涉及Spring AOP中的异常处理,可能涵盖了定义切面、通知、事务管理和...

    exception 测试

    在`TestString`这个文件中,可能包含了用于测试字符串操作的代码,比如可能会涉及到空字符串、非法字符、超出长度限制等情况,这些都可能抛出异常。测试这些情况有助于增强代码的健壮性和可靠性。 异常处理是软件...

    Java-Exception:抛出,抛出,异常,尝试,最后捕获

    2. **抛出异常(Throwing an Exception)** 当程序遇到无法正常处理的问题时,可以使用`throw`关键字主动抛出一个异常。例如: ```java throw new IllegalArgumentException("参数无效"); ``` 这会立即停止当前...

    throwing-lambdas:抛出检查异常以用于函数式接口的methodinterfaceslambdas 的包装器

    这个包允许你使用 lambdas、方法或接口,它们作为接口的唯一障碍是它们抛出一个或多个异常。 涵盖了使用的所有功能接口,以及Runnable 。 当前版本是0.5.0 。 它在 Maven 中心可用: compile( group : " ...

    异常处理.ppt异常处理.ppt异常处理.ppt异常处理.ppt异常处理.ppt

    - **抛出异常(Throwing Exceptions)**:当异常发生时,使用`throw`关键字可以明确抛出一个异常对象,通知运行时系统有异常需要处理。 - **捕获异常(Catching Exceptions)**:使用`try-catch`语句块来捕获并...

    C++程序设计教学课件:CHAPTER 13 EXCEPTION HANDLING.ppt

    C++允许函数f识别出可能导致异常的情况,并通过抛出异常(throwing an exception)的方式来通知异常的发生。 1. 抛出异常:当异常发生时,可以使用`throw`关键字创建一个在正常执行情况下不会出现的对象。这个对象...

    throwing-function, 已经检查的异常使用Java 8 功能接口 适配器.zip

    throwing-function, 已经检查的异常使用Java 8 功能接口 适配器 函数已经检查的异常使用了 Java 8 功能接口 适配器 提供了用于解决 Java 8检查的异常的快捷...你可以定义抛出checked异常的函数:ThrowingFunction, URI,

    java异常处理

    - `try` 块包含可能抛出异常的代码。 - `catch` 块用于捕获并处理特定类型的异常。 - `finally` 块确保无论是否发生异常,都会执行的代码。 - `throw` 用于显式抛出一个异常。 - `throws` 用于声明一个方法可能...

    java异常处理详细介绍

    - **抛出异常(Throwing Exceptions)**:当程序中出现异常情况时,会创建一个异常对象,并将其交给Java运行时系统。这个过程称为抛出异常。可以使用`throw`关键字显式抛出异常,或者由Java自动在遇到特定错误条件...

    Java\课件\JAVA的异常处理机制.ppt

    - **抛出异常(Throwing)**:当语义限制被违反或者预期条件未满足时,Java会抛出异常。异常对象包含异常类型和程序状态信息。 - **捕获异常(Catching)**:异常抛出后,Java虚拟机从发生异常的代码开始,向上...

    java 异常处理ppt

    `try`块包含可能会抛出异常的代码,而`catch`块则包含处理这些异常的代码。如果在`try`块中发生异常,控制流会立即跳到相应的`catch`块,而不是继续执行`try`块后面的代码。每个`catch`块都有一个特定的异常类型作为...

    Java语言程序设计6-3-java第6章(异常处理)(精).doc

    2. **异常抛出(Throwing an Exception)**:当程序中发生错误时,可以显式地抛出一个异常。例如,使用`throw new Exception("An error occurred.");`。 3. **异常捕获(Catching an Exception)**:为了处理异常,...

    JAVA的异常处理机制

    1. **抛出异常**(Throwing an Exception):当程序执行过程中出现异常情况时,会创建一个异常对象,并通过`throw`关键字抛出该异常。这个过程称为抛出异常。 2. **捕获异常**(Catching an Exception):一旦异常...

    保证Java精确异常的指令调度技术

    如果条件满足,则认为PEI引发了异常,并将控制流转移到一个特定的异常处理块(Exception Generation and Throwing Block, EGTB),在此块中生成并抛出异常。接着,根据异常的类型,系统会查找相应的异常处理单元...

    ImmutableSortedMapFauxverideShim.rar_The Exception

    "Overrides" the ImmutableMap static methods that lack ImmutableSortedMap equivalents with deprecated, exception-throwing versions.

    Java异常处理入门.pptx.pptx

    `try`块包含可能会抛出异常的代码,`catch`块则包含处理特定异常的代码。 - **抛出(Throwing)**:当发现异常时,可以使用`throw`关键字抛出一个异常对象。这可以是预定义的异常,也可以是自定义的异常。 3. **...

    java程序中的异常处理

    2. **异常抛出(Throwing Exceptions)**: - `throw`关键字用于手动抛出一个异常。在上面的例子中,当年龄值超出合理范围时(小于0或大于等于160),`setAge()`方法会通过`throw new IntegerException(age);`...

    Java Web开发异常处理方式及AOP技术

    如果try块中的代码抛出异常,相应的catch块将捕获并处理它。finally块通常用于释放资源,无论是否发生异常都会执行。 2. **Servlet的doXXX方法中的throws声明**:Servlet的doGet、doPost等方法可以声明抛出...

    java学习笔记——异常

    `try`块包含可能会抛出异常的代码,`catch`块用于处理特定类型的异常。例如: ```java try { // 可能抛出异常的代码 } catch (IOException e) { // 处理IOException } catch (NullPointerException e) { // ...

Global site tag (gtag.js) - Google Analytics