工作中,和同事对测试异常的最佳方法产生了分歧。
我是比较欣赏JUnit4的@Test(expected=FooException.class)的啦,觉得这样多清爽啊,多declarative啊,再不用写那么一大坨try-fail-catch了。
不过同事(以下简称S)不这么认为。他觉得try-fail-catch挺好的,价格便宜,量又足,我们一直用它。而JUnit 4和TestNG提供的这个功能容易引诱程序员犯错误。
S给提出了一个挑战:
public void testDoSomethingBad() {
initializeSomething();
try {
doSomethingBad();
fail();
} catch (FooException e) {}
}
这里面initializeSomething()的作用是初始化到某一个状态,这个过程不应该出错,而到了这个状态之后,doSomethingBad()才会抛异常。
然后他坚持认为这种情况是最普遍的情况。而用annotation虽然看上去很美,但是可能邪恶地诱惑程序员写出不准确的测试,造成false positive,比如,initializeSomething()抛了一个异常。
当然,我们对这种情况的常见程度各执己见。也没什么说的。但是,后来我想,其实,这个测试换成自然语言表达是什么呢?大概是这样吧?
- initializeSomething()不许出错
- 在initializeSomething()之后doSomethingBad()要出错
那么,为什么不把这两个要求写成两个测试呢?
@Test
public void testInitializeSomething() {
initializeSomething();
}
@Test(expected=FooException.class)
public void testDoSomethingBadAfterInitializeSomething() {
initializeSomething();
doSomethingBad();
}
只要我们写测试的时候不要总想着“聪明”地实现,而是直白地用代码表示需求,不就没问题了么?
再说一说我为什么这么讨厌这个try-fail-catch。它有几个我深恶痛绝的毛病。
- 它等于代码里的逻辑分支。如果没有抛异常,它执行fail(),而如果抛了异常,它进入catch()。而测试里的逻辑分支味道很坏。它让你的代码容易出错(比如,你忘了fail怎么办?测试一样是绿的,但是你的bug还躲在那)。而且,它让测试代码不能达到100%的分支覆盖率。本来如果用annotation的话,如果出现了initializeSomething()抛出异常的情况,覆盖率马上不是100%了,你可以很容易地发现问题。
- 冗长烦琐。测试写的不象spec,而象过程形代码。
- 这个try-fail-catch只在你检查Exception的时候成立。如果万一你要检查一个Error甚至是JUnit的AssertionFailedError,完了,你连fail()抛的异常也给截获了。
今天早晨,忽然灵机一动,其实,还有一个方法的。比如,在你自己的BaseTest的基类里面,你可以实现一个expectException()的函数,然后这么用:
public void testDoSomethingBad() {
initializeSomething();
expectException(FooException.class);
doSomethingBad();
}
这样,在runTest()结束前,可以检查是否存在一个exception expectation,如果有,就catch住抛出来的异常,然后进行检查。而如果没出现异常,直接就报错。这样,不就没问题了?还可以进一步抽象,弄个ExceptionExpectation的接口,这样客户代码可以灵活地登记并且重用任何的异常期待,不仅仅局限于检查异常类型和错误信息了。
当然,这是在JUnit 3.8。
分享到:
相关推荐
而对于有效性最常用的就是闰年的有效日期问题,准备这类测试用例来测试软件对于错误输入的提示和后续操作。 * web 会话测试:对于采用 b/s 结构的软件,应该注意 web 会话的处理和恢复机制,测试软件对 web 会话的...
15. **异常处理测试**:测试程序对异常输入或异常情况的处理能力。 16. **安全测试**:检查软件的安全性,防止未授权访问、数据泄露等问题。 17. **性能测试**:测试系统的响应速度、资源消耗和稳定性。 18. **...
其中,白盒测试与黑盒测试是最常见的两种测试类型。本文将针对这些基本概念及其在面试中的常见问题进行解答。 ### 白盒测试与黑盒测试 **1. 为什么需要在软件开发周期内进行测试?** 软件测试是在软件生命周期中...
- 测试异常处理机制,如输入非法字符时的处理。 - 验证循环逻辑是否正常工作。 #### 五、总结 黑盒测试和白盒测试是软件测试中不可或缺的两个方面。黑盒测试侧重于软件的功能性和用户体验,而白盒测试则更关注软件...
3. 边界条件测试:测试边界值,因为这类值最易导致错误。 4. 回归测试:修改或新增功能后,重新测试原有功能是否受到影响。 三、测试用例设计 测试用例是描述测试步骤、预期结果和测试条件的文档,它是保证测试覆盖...
有效的测试用例设计应考虑边界条件、异常情况、功能交互等方面。测试用例设计原则包括:完整性、可读性、可重复性、有效性和效率。同时,模板可以帮助规范化设计过程,通常包括预设的ID、描述、输入数据、预期结果和...
等价类划分法是黑盒测试中常用的一种技术,它将所有可能的输入数据划分成若干个等价类,选取每个等价类的代表数据作为测试用例,以覆盖尽可能多的边界情况和异常情况。 白盒测试,又称为结构测试或逻辑测试,侧重于...
边界值分析是一种测试方法,重点在于选取边界条件或临界值进行测试,因为这些往往是错误最可能发生的地方。 三、自动化测试 1. **自动化测试的优点与缺点?** 优点:提高效率,减少人工错误,节省时间,适合重复...
此阶段还需要考虑如何组织测试数据、如何处理异常情况等问题。 ##### 2.3 自动化测试实施 在完成测试设计后,进入实际的测试脚本编写和执行阶段。这一过程中需要不断地调试和完善测试脚本,以确保其能够准确无误地...
实验旨在让参与者掌握自动化测试工具,如QTP(QuickTest Professional,现已被HP Unified Functional Testing替代)和LoadRunner,并学习如何有效地编写测试报告。 功能自动化测试主要使用QTP进行。QTP是一款功能...
虽然本书还很难覆盖完美测试应具备的各种方法和实践,但目的在于抛砖引玉,使读者能通过最有效的手段(包括方法、技术和工具)完成所有必要的测试,实现事先所要求的需求和代码的测试覆盖率,最终能准确地给出软件...
灾难恢复测试是信息技术领域中一项至关重要的活动,旨在验证和确保在面临突发灾难或系统故障时,能够迅速有效地恢复关键业务系统和数据,从而最小化业务中断的影响。以下是对这份“灾难恢复测试报告”的详细解析。 ...
- **定义**:最小规模的测试,针对某个具体的功能或代码块进行验证。 - **目的**:确保每个代码单元按预期工作,有助于早期发现问题。 - **实施者**:通常由开发人员完成,因为需要了解内部程序设计和编码细节。 ##...
Junit 是Java语言中最常用的单元测试框架,非常适合初学者学习和使用。本课件主要介绍了如何使用Junit进行单元测试。 首先,我们需要导入Junit相关的包,通常为`junit.framework.*`。这将包含运行测试所需的类和...
- 测试用例总数计划为500组,其中200组为预期的正常工作量,300组为最繁重工作量。 - **里程碑任务**: - 2021年4月1日至2021年4月1日:制定测试计划 - 2021年4月2日至2021年4月2日:设计测试用例 - 2021年4月3...
综上所述,手工测试和自动化测试各有优势和局限,在实际应用中应根据项目特性、团队能力、成本预算等多方面因素综合考虑,选择最合适的测试策略。在很多情况下,结合两者的优势,实施混合测试策略可能是最佳选择,既...
试题还涉及到其他问题,如阶段评审与同行评审的区别、软件测试的定义、集成测试的过程、文档测试的实施、白盒测试的方法、系统测试计划的同行评审必要性、Alpha测试与Beta测试的差异、不同测试类型的区别(如负载...