引用:Andrea Arcuri, Gordon Fraser, and René Just.2017. Private API Access and Functional Mocking in Automated Unit Test Generation. In Proceedings of the International Conference on Software Testing, Verification and Validation (ICST), March 13-17 2017, pp. 126-137.
摘要:
在测试过程中,并非所有面向对象的代码都可以被简单的方法测试到。代码依赖对象可能很难甚至无法实例化,面向对象的封装会使得简单代码变得难以测试。当发生这种情况时,开发人员可以使用模拟复杂依赖关系的模拟对象,或者使用Java反射绕过面向对象的封装,直接访问私有API。在本文中,我们通过扩展EvoSuite单元测试生成工具以及直接访问私有API的能力来研究这个问题,并使用流行的Mockito框架创建模拟对象。但需要注意的是,这不会影响生成测试的有用性:如果重命名字段,即使该重命名是保留语义的重构的一部分,访问私有字段的测试也可能会失败。这样的失败不会揭示真正的回归错误,但这却是误报并且会浪费开发人员审查和修复测试的时间。我们对SF110和Defects4J基准测试的实验证实,在代码覆盖率和错误发现方面存在改进,同时也存在相应的误报,但是误报的规模相对较小。
关键词:单元测试,私有API访问,功能模拟,代码覆盖率
1. 背景:
1.1 私有API访问
通常情况下,与被测试类(CUT)位于同一包中的测试用例可以直接访问所有public、protected、package-private方法和字段。但是,它无法访问private方法。测试数据生成的一个目标是最大化CUT的覆盖范围,其中还包括其所有私有方法。可以采用Java的反射API直接调用私有方法。
1.2 功能性模拟
模拟是单元测试中的一种常见方法,通过使用替换类而不是原始类来替换类与其依赖项,使用Mockito框架创建模拟对象,模拟对象可用于验证它们执行的调用顺序。
1.3 单元测试生成中的误报
使用自动生成的测试至少有两种可能的情况:(1)使用手动检查测试,检查它们中是否有捕获CUT的错误行为;(2)使用测试进行回归测试。
误报产生原因:(1)测试可能代表不切实际的执行或使用CUT;(2)在回归测试期间进行错误的测试或过度限制性假设的测试可能会失败。
2. 方法:
我们将私有API访问(PA)和功能模拟(FM)集成到EvoSuite中。
2.1 EvoSuite中基于搜索的测试生成
将反射和模拟集成到EvoSuite的搜索算法中,使用了两个访问点:(1)搜索运算符将新对象和新调用插入测试用例;(2)静态分析通知修改可选的操作符。它们对搜索期间构建的调用序列存在影响。
2.2 集成私有API访问
我们创建了一个辅助类PrivateAccess对EvoSuite进行扩展,它是运行库的一部分,在测试执行期间可用。此类提供静态方法,如callMethod:PrivateAccess.callMethod(Bar.class,bar,"aPrivateMethod