文章目录
- 目的是测试模块而非单个 function
State and Programs
- Data = State.
- State is accessed & manipulated via specific operations. 通过特定操作访问和操作状态。
- Collections of these operations = Module. 这些操作集合 = 模块。
- Benefits:
- Separation of interface and implementation. 接口和实现分离。
- Treats operations as a black box. 将操作视为黑盒子。
- Data details concealed; changes to data don’t affect users if the interface remains consistent. 数据细节隐藏;如果接口保持一致,则对数据进行更改不会影响用户。
Testability of State-Based Programs
-
testability 取决于 可控性 和 可观察性
-
例如,考虑一个允许操作和访问堆栈的模块。该类的操作允许我们将元素推入堆栈,查看堆栈顶部,弹出堆栈顶部的元素,并检查堆栈是否为空。
-
按照之前的知识,如果我们要测试一个 funciton 或者模块,我们根据其输入的参数设计等价类,并选用合适的 test case,然后我们可以根据预期的输出来观察 funciton 运行的结果。
-
但是这个堆栈并非如此;push操作不需要堆栈参数,这意味着无法通过其接口控制push操作。此外,一旦将元素推入堆栈,我们无法直接观察到堆栈的值。 因此,作为堆栈模块的操作不容易被控制或观察到。
-
所以,不能孤立地测试 push 这个操作,要测试 push 这个 function,我们就必须借助其他的 funciton 或者模块(例如 isFull, isEmpty)为 push 的行为提供可观察性,来提高 testability.
intrusively test 侵入性测试
- 一种增加 testability 的方式是 “intrusively test”:
- 要求测试人员修改代码,暴露那些 hidden 的部分,打破了 information 的 hiding aspect; 测试完之后再给修改回去
- 这有明显的缺点:
- 它不测试要使用的实现,而是其修改的版本(因为测试人员需要另外增加代码);
- 如果模块中的基础数据类型发生变化,则必须同时更改测试;并且
- 它忽视了对同一数据进行操作的操作之间存在内在联系,并且必须一起进行测试。
Non-intrusive test 非侵入测试
- 利用模块定义的操作将模块状态设置为所需的测试值,执行必要的测试,然后再次使用这些操作查询测试结果。 以堆栈类为例,在测试 “向包含一个元素的堆栈推送元素行为” 时,我们首先使用push 将一个元素推送到空堆栈中 (设置了我们测试所需的状态) ,然后再推送另一个元素进行测试,并使用 top 和 pop 操作查看模块状态。
- 也就是说,非侵入测试是通过构建特殊的 状态 来进行进一步测试的
java和其他工具的实践
- java 提供 protected,这意味着如果我们可以继承该类,则可以访问类中的变量。这使得我们能够 passively 观察变量的值而不改变模块本身。这是一种介于 intrusive 和 non-intrusive 的方法
- 其他工具提供了非侵入式观察数据的方法,例如在程序中插入断点,并允许测试人员在该断点处观察程序状态。
有限状态机进行单元测试(Unit testing with FSA)
-
Definition: FSA is a model of behavior consisting of finite set of states with actions that move the automaton from one state to another. FSA是一个行为模型,由有限状态集合和将自动机从一个状态转移到另一个状态的操作组成。
-
关于模块,有限状态自动机(FSA)中的 每个状态对应着模块中一组状态。状态之间的转换对应着模块中的操作。转换可以使用前置谓词来指定必须满足的前提条件。