软件构造(二)软件测试与测试优先的编程

1.软件测试

测试是提高软件质量的重要方法。一个好的测试要有以下特点:能发现错误、不冗余、最佳特性、不复杂也不简单。但是再好的测试也存在缺陷

测试大致可分为几个阶段:

单元测试(Unit Testing): 测试部分代码的功能

集成测试(Integration Testing): 多个类、包、组件和子系统组合的测试

系统测试(System Testing): 测试一个完全集成的系统,以验证该系统满足其要求,从而在其最终配置中执行软件

在这里插入图片描述
当然,还有其他的其他测试类型:安装测试、兼容性测试、烟雾和理智测试等等

静态测试(Static Testing): 在没有实际执行程序的情况下执行,例如检查代码的语法等等

动态测试(Dynamic Testing): 使用一组给定的测试用例来执行编程代码

注意! 测试(Testing)与调试(Debugging)的不同。测试(Testing)是发现代码是否存在错误,调试(Debugging)是已知有错误,去找到错误代码并消除错误。

白盒测试(White-box Testing): 源代码已知

黑盒测试(Black-box Testing): 源代码未知

想要写出好的代码测试是很困难的。首先,不可能列出所有的测试用例,因为样本数量巨大;其次,随机碰运气也很难,除非你的程序全是错误,或者你欧的一批;最后,和其他自然科学的规律性不同,程序出错不具有规律,因此很难通过基于样本的统计数据对程序进行测试。

Not only “make it fail”, but also “fail fast”.

2.测试用例

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

一个好的测试用例具备以下特点:

  1. 最可能发现错误
  2. 不重复、不冗余
  3. 最有效
  4. 既不简单也不复杂

3.测试优先编程

测试优先编程(Test-first Programming),即先写测试,再根据测试写源代码。

流程:

  1. 根据功能写规约(Spec)
  2. 写出符合规约的测试用例
  3. 最后写源代码,并且不断测试修改,直到代码通过测试

优点:

  1. 可以帮助你更好的了解规约,同时也能帮你提前发现可能存在于规约中的错误
  2. 节省大量的时间(相比于后写测试)
  3. 可确保程序的可测试性
  4. 确保每个程序特征的测试都撰写完成

规约(Specification)
函数的规约是对函数行为的描述,包含以下三项:
1.参数类型
2.返回值的类型
3.约束和它们之间的关系。

在这里插入图片描述

4.单元测试

单元测试(Unit Testing)是针对软件的最小单元模型,隔离各个模块开展测试,能更好的定位错误。

注意事项:

  1. 对单元接口进行测试,即测试输入输出
  2. 确保在进行测试的过程中,数据前后的一致性,不发生变化
  3. 所有语句至少执行一次
  4. 对边界条件进行测试
  5. 最后,测试所有错误处理路径

因为构件不是一个独立的程序,所以通常要为每个单元测试开发驱动模块和桩模块
驱动模块: 类似一个“主程序”,它接受测试用例数据,将这些数据传递给待测试的构件,并打印结果
桩模块: 模拟被测试的模块所调用的模块,与主模块相连,接受或传递被测模块的数据

5.使用JUnit进行自动单元测试

JUnit是一个Java语言的单元测试框架

在JUnit中,每个测试用例前都加上 @Test 标签

单元测试方法通常包含一个或多个对被测试模块的调用,然后使用assertEquals、assertTrue和assertFalse等断言方法检查结果
在这里插入图片描述
JUnit断言方法中的参数顺序:一般来说,第一个参数是期望结果(expected result);第二个参数是实际执行结果(actual result)

测试类可以包含任意数量的@Test方法,当您使用JUnit运行测试类时,这些方法是独立运行的。哪怕有些方法并不能通过测试

注意!在IDE中,Test的文件结构应该和源码的文件结构一样。
在这里插入图片描述

6.黑盒测试

黑盒测试(Black-box testing):用于检查代码的功能,不关心内部实现细节

黑盒测试能找到以下类型的错误:

  1. 功能不正确或缺失
  2. 界面错误
  3. 数据结构或外部数据库访问错误
  4. 行为或性能错误
  5. 初始化和终止错误

6.1 通过划分选择测试用例

等价类划分:将被测试函数的输入域划分为等价类,从等价类中选择测试样例

通过等价类选出最具代表性的测试用例,从而大幅降低测试用例数量
在这里插入图片描述

6.2 包含边界的划分

边界值分析(BVA): 选择边界值测试用例,一种补充等价划分的测试用例设计技术

大量的错误发生在边界。

覆盖划分的两个极端:

  1. 笛卡尔积: 多个划分维度上的多个取值,要组合起来,每个组合都要有一个用例
    测试完备,但用例数量多,测试代价高
  2. 覆盖每个取值:每个维度的每个取值至少被1个测试用例覆 盖一次即可
    测试用例少,代价低,但测试覆盖度未必高

7.白盒测试

白盒测试(Whitebox testing)要考虑内部实现细节

通过代码的执行路径设计测试用例,白盒测试一般较早执行

使用白盒测试方法,你要保证:

  1. 确保模块内的所有独立路径至少已执行一次
  2. 在正确和错误的方面做出所有合乎逻辑的决定,
  3. 在其边界和操作边界内执行所有循环,
  4. 使用内部数据结构以确保其有效性

典型的白盒测试方法称为“独立/基路径测试

独立/基本路径测试:对程序所有执行路径进行等价类划分,找出有代表性的最简单的路径(例如循环只需执行1次),设计测试用例使每一条基本路径被至少覆盖1次

8.覆盖率的测试

测试应该考虑测试用例的代码覆盖率(Code coverage)

代码覆盖率高,说明未检测到的错误的比率更低,但需要更多的测试用例

以下有几种代码覆盖率:

  1. 函数覆盖
  2. 语句覆盖
  3. 分支覆盖
  4. 条件覆盖
  5. 路径覆盖

测试效果:路径覆盖 > 分支覆盖 > 语句覆盖,但是越强就需要更多的测试用例。老孙权了。 再但是,100%的路径覆盖是不可行的,需要指数大小的测试套件来实现

最彻底的白盒方法是覆盖程序中的每一条路径,但是 几乎不可能执行每条路径。举个栗子,一个程序包含一个需要执行20次的循环。它包括520个不同的执行路径。假设测试每条路径需要1ms,则完成所有路径的测试需要3170年

实用工具:EclEmma(最新版Eclipse自带)、一般IDEA中也是自带覆盖率检测的运行选项的。没有的话,Coverage插件多的一批

9.自动化测试和回归测试

自动化测试(Automated testing)意味着运行测试并自动检查结果,就比如JUnit就是一个自动化的测试框架

回归测试(Regression testing):代码经过了修改就要再次进行一遍所有的测试

10.记录测试策略

单元测试策略是ADT设计的补充文档

与测试优先编程的思想相一致,建议写下设计测试用例所依据的测试策略(如分区和边界)

目的: 在代码评审过程中,其他人可以理解你的测试,并评判你的测试是否足够充分

在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值