HIT软件构造课程复习笔记(七)

6.3 断言与防御式编程

断言

断言:在开发阶段的代码中嵌入,检验某些“假设”是否成立。若成立,表明程序运行正常,否则表明存在错误。 出现AssertionError,意味着内部某些假设被违反了。断言即是对代码中程序员所做假设的文档化,也不会影响运行时性能 (在实际使用时,assertion都会被disabled)
语法:assert condition : message;
所构造的message在发生错误时显示给用户,便于快速发现错误所在。
断言可以用来确认内部不变量/表示不变量/控制流不变量/方法前(后)置条件等内容,比如检测方法的传入参数和返回值的正确性

断言主要用于开发阶段,避免引入和帮助发现bug,实际运行阶段,不再使用断言,这样可以避免降低性能。并且不要在断言语句中加入执行操作,因为断言语句一旦被判伪便不再运行,程序之外的事,不受你控制,不要乱断言,外部错误要用异常进行处理

对于程序而言,断言检测其正确性,错误/异常处理检测其健壮性,使用异常来处理你“预料到可以发生”的不正常情况,使用断言处理 “绝不应该发生”的情况。如果参数来自于外部(不受自己控制),使用异常处理;如果来自于自己所写的其他代码,可以使用断言来帮助发现错误(例如postcondition就需要)断言和异常处理都可以处理同样的错误,开发阶段用断言尽可能消除bugs在发行版本里用异常处理机制处理漏掉的错误

防御式编程

防御性编程是一种防御性设计形式,目的是确保软件在不可预见的情况下继续发挥作用,这可以被看作是减少或消除了墨菲定律的作用。

可以用来防御式编程的技术:

保护程序不受无效输入影响:对来自外部的数据源要仔细检查,例如文件、网络数据、用户输入等;对每个函数的输入参数合法性要做仔细检查,并决定如何处理非法输入

设置路障:一个控制损害的策略。其原理类似于船体中有隔离的隔间和建筑物中的防火墙,指定某些接口作为“安全”区域的边界,检查跨越安全区域边界的数据是否有效,如果数据无效,则做出反应。
类的public方法接收到的外部数据都应被认为是dirty的,需要处理干净再传递到private方法——隔离舱;隔离舱外部的函数应使用异常处理,隔离舱内的函数应使用断言,代理模式在这里也有很合适的应用。

6.4 代码调试

什么是debug

bug:程序中的一种错误,它导致程序以一种非预期的方式执行
防御式编程->测试->debug
debug:确认程序错误根源的位置并修复它,占用了大量的开发时间。Debug是测试的后续步骤,测试发现问题,debug消除问题。debug的难度在于“症状”和“原因”可能相隔很远(高耦合导致的结果),或是当其他bug被修复后,该bug消失了…因为人工错误导致bug的症状难以有效追踪,有些症状是由计时/定时等时间原因导致的,难以重现出错时的输入数据,由于外部软硬件环境变化,导致间歇性的症状,甚至还有分布式导致的问题。

debug过程

重现-诊断-修复-反思

重现:找到一种可靠、方便地按需重现问题的方法。从最小的测试用例集开始复现错误,确定有哪些因素跟bug相关,将这些因素找出来并变化它们的值, 确保你的bug复现环境跟用户发现bug的环境尽可能保持一致,注意软件版本、运行环境和输入数据

诊断/定位:构建假设,并通过执行实验来测试它们,直到确信已经确定了错误的潜在原因。
诊断策略:
1.测量:一种代码,它不会影响软件的行为,而是提供洞察软件行为的原因(比如日志),可以通过它您收集和整理数据,计算分析任意代码,并测试相关条件
2.分治:一种搜索策略,它可以提供一个快速简单的方法来排除大量的候选部分。防狼围栏算法:平原找一匹狼,加一次围栏就判断狼在里还是外,之后不断循环这一过程使得围栏越来越小即可。
3.切片:指找出程序中有助于计算特定值的部分。当出现故障(在程序的某个特定点出现一个坏值)时,该值的切片由帮助计算该坏值的代码组成
4.寻找差异:充分利用版本控制系统,找出在哪个commit之后出现了bug症状。对于这类问题,在回归搜索中有一个很有价值的工具——源代码控制系统。Git源代码控制系统以Git bisect命令(“Wolf fence”)的形式为其提供直接支持。(二分查找)
基于差异的调试:
两个测试用例,分别通过/未通过。通过查找二者所覆盖的代码之间的差异,快速定位出可能造成bug的代码行。 也可以查找其他方面的差异:软硬件环境、JVM参数配置、输入文件…
5.符号化调试:不需输入特定的值,使用“符号值”(而非“实际值”)作为输入, 解释器模拟程序执行,获得每个变量的“符号化表达式”,从而可判断是否执行正确。
6.调试器:它允许我们在代码执行时检查代码、设置断点、单步执行和检查程序状态。它在开发生命周期的三个不同点上特别有用:在最初的开发过程中,单步执行代码有助于说服我们,它真正在做的事情与我们想要实现的事情是一致的;如果我们有一个关于代码为什么以特定方式运行的理论,我们可以使用调试器来证实或驳斥这个理论;最后,调试器帮助我们探索以我们根本不理解的方式运行的代码

修复:设计并实现解决问题的变更方案,维护和改进软件的整体质量

反思:从错误中吸取教训。例如哪里出了问题,同样的问题还有其他需要解决的例子,能做什么来确保同样的问题不再发生等

假设-检验法:收集bug相关数据,观察数据,做出bug原因的假设,再决定如何验证,最后通过工具验证假设是否成立

debug工具

暴力破解法BF:看内存导出文件、到处println()、使用自动化调试工具

内存转储:硬盘上的一个文件,包含某一特定时间内进程的内存内容的副本,当进程因某种内部错误或信号而中止时产生。当程序中止时,可以进行内存转储,以检查程序在崩溃时的状态。

堆栈跟踪:可以通过调用Throwable类的printStackTrace方法来访问堆栈跟踪的文本描述。更灵活的方法是getStackTrace方法,它会产生一个StackTraceElement对象数组,您可以在程序中对其进行分析。静态方法Thread.getAllStackTraces生成所有线程的堆栈跟踪

printf:在程序内部各部分展示程序执行时的动态信息,比使用静态的dump 分析更有效,一旦软件对外发布,所有用于debug的print语句都要去除或禁用。

日志:通过设定日志级别来确定要log哪些信息, log结果可被多种渠道加 以处理,可通过设定条件进行过滤,并输出为多种格式,可使用层次化的多个日志记录器

编译警告信息: 把编译器的warning level调到最高级别,消除所有warning,学着把编译器当作自己的老师,搞清楚每一个warning,并在后续代码中避免

6.5 软件测试与测试优先的编程

软件测试

软件测试是提高软件质量的重要手段,确认是否达到可用级别(用户需求)并关注系统的某一侧面的质量特性。 即使是最好的测试,也无法达到100%的无错误,残留缺陷率达到每千行1-10个已经是工业级软件。

单元测试:指验证特定代码段功能的测试,通常在功能级别。针对软件的 最小单元模型开展测试,隔离各个模块,容易定位错误和调试
集成测试:由多个程序员或编程团队创建的多个类、包、组件和子系统的联合执行。
系统测试:测试一个完全集成的系统,以验证该系统满足其要求,从而执行该软件的最终配置。
静态测试:在不实际执行程序的情况下执行。
动态测试:描述了对代码动态行为的测试,它使用一组给定的测试用例实际执行已编程的代码。
白盒测试:对程序内部代码结构的测试。
黑盒测试:对程序外部表现出来的行为的测试。
测试发现错误,调试消除错误,测试的难点在于软件行为在离散输入空间中差异巨大,且无统计分布规律可循

测试用例:输入+执行条件+期望结果

测试优先的编程

含义:写代码前先写测试用例。先写spec,再写符合spec的测试用例,再 写代码、执行测试、有问题再改,再执行测试用例,直到通过它(写测试用例,就是理解、修正、完善你的spec设计的过程)

黑盒测试

黑盒测试:用于检查代码的功能,不关心内部实现细节。检查程序是否符合规约,用尽可能少的测试用例,尽快运行,并尽可能大的发现程序的错误。

等价类划分:基于等价类划分的测试:将被测函数的输入域划分为等价类,从等价类中导出测试用例。针对每个输入数据需要满足的约束条件,划分等价类,每个等价类代表着对输入约束加以满足/违反的有效/无效数据的集合。相似的输入,将会展示相似的行为,故可从每个等价类中选一个代表作为 测试用例即可

边界值分析:大量的错误发生在输入域的“边界”而非中央,边界值分析方法是对等价类划分方法的补充

笛卡尔积:全覆盖,多个划分维度上的多个取值,要组合起来,每个组合都要有一个用例,但并非所有组合情况都可能,覆盖每个取值最少1次即可

测试覆盖度

代码覆盖度:已有的测试用例有多大程度覆盖了被测程序(通常用百分比衡量覆盖度),代码覆盖度越低,测试越不充分,但要做到很高的代码覆盖度,需要更多的测试用例,测试代价高。

测试效果:路径覆盖>分支覆盖>语句覆盖
测试难度:路径覆盖>分支覆 盖>语句覆盖

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值