首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

junit 测试错误(转)

2013-01-18 
junit 测试异常(转)? 今天做单元测试,要求做下路径覆盖,于是乎要对异常进行测试了。这个第一次搞,不知道怎

junit 测试异常(转)
? 今天做单元测试,要求做下路径覆盖,于是乎要对异常进行测试了。这个第一次搞,

不知道怎么下手,当遇到异常,马上终止测试(测试没有通过),但是不在catch中写的话,有不符合要求,于是网上转了下。算是解决了。

?测试是否抛出正确的异常(Test throwing the right exception)博客分类:
    ?软件测试Java代码??junit 测试错误(转)
    1. public?void?testConstructorDiesWithNull()?throws?Exception{??
    2. ??try{??
    3. ??????Fraction?oneOverZero?=?new?Fraction(1,0);??
    4. ??????fail("Created?fraction?1/0!?That's?undefined!");??
    5. ????}??
    6. ?catch(IllegalArgumentException?excepted){??
    7. ?????assertEquals("denominator",excepted.getMessage());??
    8. ??????}??
    9. }??

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

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

    一个更面向对象的解决办法?
    先看一个匿名内部类?
    Java代码??junit 测试错误(转)
    1. public?void?testForException(){??
    2. ??assertThrows(MyException.class,?new?ExceptionClosure(){??
    3. ?????public?Object?execute(Object?input)?throws?Exception{??
    4. ??????????return?doSomethingThatShouldThrowMyException();??
    5. ?????????}??
    6. ????});??
    7. ??}??

    虽然有人觉得Java的匿名内部类不太好读,但这个方法的意图再明显不过了:"测试这段代码是否抛出期望的异常"。可以按如下的方式实现assertThrows()方法:?
    Java代码??junit 测试错误(转)
    1. ??public?static?void?assertThrows(Class?expectedExceptionClass,?ExceptionalClosure?closure){??
    2. ????String?expectedExceptionClassName?=?expectedExceptionClass.getName();??
    3. ??
    4. ?try{??
    5. ???????closure.execute(null);??
    6. ???????fail("Block?did?not?throw?an?exception?of?type"+expectedExceptionClassName);??
    7. ?????}??
    8. catch(Exception?e){??
    9. ???assertTrue("Caught?exception?of?type?<"?+?e.getClass().getName()??
    10. ??????????????+">,?expected?one?of?type?<"??
    11. ??????????????+expectedExceptionClassName+">",??
    12. ??????????????expectedExceptionClass.isInstance(e));??
    13. }??
    14. }??

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

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

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

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

热点排行