单元测试
什么是单元测试
单元测试是开发者编写的一小段代码,用于检验被测代码的一个很小的、很明确的功能是否正确。通常而言,一个单元测试是用于判断某个特定条件(或者场景)下某个特定函数的行为。
构建单元测试
测试代码必须要做以下这几件事情:
- 准备测试所需要的各种条件(创建所有必须的对象,分配必要的资源等等)。
- 调用要测试的方法。
- 验证被测试方法的行为和期望是否一致
- 完成后清理各种资源
JUnit的各种断言
Junit提供了一些辅助函数,用于帮助你确定某个被测试函数是否工作正常。通常而言,我们把所有这些函数统称为断言。它让你可以确定:某条件是否为真;两个数是否相等,或者不等,或者其他一些情况。
assertEquals
|
|
这是使用得最多的断言形式。在上面的参数中,expected是你的期望值
(通常都是硬编码的),actual是被测试代码实际产生的值,message是~个 可选的消息,如果提供的话,将会在发生错误的时候报告这个消息。当然, 你完全可以不提供这个message参数,而只提供expected和value这两个值。
注意事项
书中的assertEquals方法已经不建议使用,建议使用assertArrayEquals方法
assertNull
验证一个给定的对象是否为null(或者为非null),如果答案为否,则将会失败
assertSame
验证expected参数和actual参数所引用的是否为同一个对象,如果不是
的话,将会失败。
assertTrue
验证给定的二元条件是否为真, 如果为假的话, 将会失败。
fail
该断言将会使测试立即失败,通常被用于标记某个不应该被到达的分支。
使用断言
一般而言,一个测试方法会包含有多个断言,因为你需要验证该方法的,多个方面以及内在的多种联系。当一个断言失败的时候,该测试方法将会被中止一一从而导致该方法中剩余的断言这次就无法执行了。此时你不能有别的想法,而只能是在继续测试之前先修复这个失败的测试。依此类推,你不断地修复一个又一个的测试,沿着这条路径慢慢前进。
测试哪些内容
6个值得测试的具体部位,把这6个方面统称为:Right-BICEP
- Right: 结果是否正确
- B:是否所有边界都是正确的
- I: 能查一下反向关联吗
- C:能用其他手段交叉检查一下结果吗
- E: 你是否可以强制错误条件发生
- P:能否满足性能要求
CORRECT边界条件
- 一致性(Conformance): 值是否符合预期的格式
- 有序性(Ordering): 一组值该有序的还是无序的
- 区间性(Range): 值是否存在一个合理的最大值和最小值的范围之内
- 引用,耦合性(Reference): 代码是否引用了一些不受代码本身直接控制的外部因素
- 存在性(Existence): 值是否存在(例如:非null,非零,包含于某个集合等)
- 基数性(Cardinality): 是否恰好有足够的值
- 时间性(Time):所有事情是否都是按顺序发生的?是否在正确的时间?是否及时?
Mock对象
mock对象是真实对象在调试期的替代品
使用mock步骤
- 使用一个接口来描述这个对象
- 为产品代码实现这个接口
- 以测试为目的,在mock对象中实现这个接口
好的测试所具有的品质
- 自动化:测试自动化和检查结果自动化,对于测试需要的任何条件,都应该让它们成为测试自身的一个自动化组成
- 彻底的:单元测试覆盖率的问题,应考虑对所有边界进行测试
- 可重复:每个测试应该是独立于其他测试的,而且必须独立于周围的环境,想能达到的目标是测试应该能以任意顺序一次一次的运行,并且产生相同的结果
- 独立的:测试应该是简洁精炼的,每个测试有针对性,并且独立于环境和其他测试
- 专业的:使用和产品代码相同的专业水准来编写和维护测试代码