Skip to content

Record 202307

1 算法

类过滤器:

  1. anonymousMethodFilter
  2. abstractClassFilter

函数过滤器:

  1. constructorMethodFilter
  2. anonymousClassFilter
  3. abstractMethodFilter

1.1 初始种群生成

问题:

  1. EvoSuite 怎么实现的?论文?
  2. 个体的方法调用序列是什么序列?
  3. EvoSuite 实际生成的测试用例是怎么样的?

1.2 选择

1.3 突变

1.4 重组

2 框架

2.1 断言生成

限制:仅适用于基础数据类型的返回值

进度:

  • 使用 print 语句获取方法调用返回结果
  • 通过 OutputStream 获取返回结果的类型和值,并存储在 TestCase
  • TestCase 转化为 Jimple 时生成断言

方案 1

  1. 生成正常的 jasmin class;
  2. 使用 java agent 做插桩,收集待测方法的返回值;
  3. 插桩信息返回:
    1. 使用 socket 将返回值传给算法;
    2. 使用 java agent 在测试用例方法体的最后添加 print 语句,通过 outputStream 的方式传给算法。

方案 2

  1. TestCase 转化为 SootMethod 时,如果最后一个方法调用有基础数据类型的返回值,则添加 print 语句将方法调用的结果输出(仅在遗传算法中做此特殊转换);
  2. 获取 fitness 时,通过 outputStream 的方式获取方法调用的输出。

2.2 Android Test 生成

问题:

  1. 如何在命令行中运行 android test?
  2. 如何获取覆盖率?
  3. 如何判断是否为 android test?
  4. 怎么样的 android test 是有意义的?

2.3 测试用例约简

2.4 测试用例重用

3 进度

输出日志截图

4 记录

4.1 JaCoCo Commands

How to use kotsuite agent and jacoco agent to generate test case coverage?

# Collect code coverage information to exec file using kotsuite and jacoco agent
java \
-javaagent:"./kotsuite-agent/build/libs/kotsuite-agent-1.0-SNAPSHOT.jar=com.example.myapplication.TempCalleePrintHelloRound0.test_printHello_1" \
-javaagent:"./libs/org.jacoco.agent-0.8.10-rumtime.jar=includes=*,destfile=./output/jacoco-coverage.exec,output=file" \
-cp "example-projects/MyApplication/app/sootOutput/:libs/*" \
KotMain

# Analyze exec file to generate HTML report
java -jar libs/org.jacoco.cli-0.8.10-nodeps.jar report output/jacoco-coverage.exec --classfile="./example-projects/MyApplication/app/sootOutput/" --sourcefile="./example-projects/MyApplication/app/src/main/java" --html output/report

4.2 Soot

PrimType

5 测试 Android 项目

Simple-Gallery

待测类:50 个

graph LR

class1[587] --!anonymous--> class2[107]
class2 --!private--> class3[106]
class3 --!abstract/!interface--> class4[97]
class4 --!data--> class5[65]
class5 --"has method"-->class6[45]

待测函数:239 个

6 其它测试生成工具

7 问题

  1. 构造函数问题:无法构造待测类的对象
  2. 总共的 public 方法有 2396 个,大部分方法都是与 Android 相关(所在类是 Android 平台类的父类或函数参数为 Android 平台类)。
    1. 去除 Android 相关方法和数据类后,只剩下 248 个待测方法,其中的 205 个为 Config 类中的 get()set() 方法,18 个为数据类(未被成功过滤)中的 get()set() 方法。
    2. 剩余方法为 25 个。
  3. 因此必须考虑 Android 相关类的测试生成。
  4. 其他测试生成工具如何测试生成?
  5. 人工如何编写测试用例?

7.1 Android 相关方法测试用例生成

问题:无法直接使用构造函数构造对象

8 参考链接

9 测试生成算法思考

需求:

  • 针对什么生成测试用例?每一个 public 方法?那 override 方法和生命周期函数要不要生成?
  • 生成什么样的测试用例?
  • 如何生成?
    • activity 如何获取?
    • 状态如何改变?
      • 状态不是有方法序列改变,而是由动作改变,且不是所有方法序列都是合理地
      • 而目前遗传算法中的个体是方法序列,需要改为动作序列吗?

思路:existing tools -> test script → unit test

问题:

  • 传统的针对每一个 public 生成测试用例的思路不可行
  • 遗传算法针对方法调用序列以修改状态的方式不可行,因为有大量的方法都是父类的方法,且不可被直接调用
  • activity 如何获取?什么时候需要 mock?如何 mock?

解决方案:

  • Unit Test:只有少数的方法需要,采用传统思路
  • Android Test:大部分,采用新思路

进度:

  • 一期只做 unit test 部分
  • 后面再做 android test 部分

下一步:

  • 了解人工编写的 android test 长什么样,再来确定算法
  • 做一次汇报

10 断言生成算法

局限性:只支持基本数据类型

思路一

  1. 生成正常的 jasmin class;
  2. 使用 java agent 做插桩,收集待测方法返回值;
  3. 使用 Socket 将返回值传给算法。(优点:可扩展性更高,可以收集其他运行时信息)
  4. 或 添加 println 语句,通过 outputStream 的方式传给算法。

思路二

  1. 转换为 jimple 时,将最后一条语句的结果 print 出来;
  2. 收集 fitness 时,通过 outputStream 的方式获取返回结果。

11 近期问题

  1. Android Test 的测试目标是 UI 测试吗?即每个测试用例是否对应一个用户动作序列?
  2. 测试用例集要针对哪些方法计算圈复杂度覆盖率?Override 方法(生命周期方法)是否考虑在内?
  3. 生成的测试用例集的圈复杂度覆盖率是用什么工具评估的?如 JaCoCo 等。
  4. Android Test 是不是需要针对每一个 public 方法生成测试用例集?如果是,那么是否需要对 Override 方法生成测试用例集?

回复

  1. 他们是想表达单元测试,是不在意 UI 测试的,他们是管理整个测试环节,所以很多细节他们没掌握。但实际场景中,确实是有涉及 UI 的很多。我也说了Activity 的测试生成问题。我让他们发内部写好的带有 Activity 的单元测试用例给你。这样我们能够容易考虑命令行和 android test的测试用例差异。
  2. 对针对public的方法写单元测试。对于override,方法A复写方法B,只测方法A。
  3. 他们用的Sonar计算圈复杂度,我印象中Sonar就是用的Jacoco的实现,你可以核对一下。

SonarQube