简介
Major 是一个轻量级变异测试工具,其工作原理主要分为两步:
- 在编译过程中生成+嵌入变异体
- 执行变异体进行变异分析
安装
官网:http://mutation-testing.org/
官方教程:http://mutation-testing.org/doc/major.pdf
参考论文:https://homes.cs.washington.edu/~rjust/publ/major_issta_2014.pdf
-
下载
前往 http://mutation-testing.org/downloads/
下载新版本的MAJOR, 1.3.0以上的版本已经适配Java8 -
环境配置
安装OpenJDK-8 (Ubuntun 16.04 安装JDK-7会比较繁琐,建议JDK-8;如果想不开想要安装的话,请参考https://segmentfault.com/a/1190000014979994)
# 编辑环境变量文件:
sudo gedit /etc/profile
# 在文件末尾输入以下内容
export MAJOR_HOME=MAJOR_PATH
export PATH=${MAJOR_HOME}/bin:$PATH
# 输入以下命令使设置生效:
source /etc/profile
# 验证 Javac 版本:
javac -version
# 输出内容如下:
javac 1.7.0-Major-v1.3.5
# 验证 Ant 版本:
ant -version
# 输出内容应类似于此:
Apache Ant(TM) version 1.8.4-Major-v1.3.5 compiled on July 18 2019
3.编写MML脚本【可选步骤】
为你的类编写MML脚本,在脚本中指定变化文法,变异算子生成方法,和希望被测试的类别;
以程序中自带的作为例子;
当然,你也可以使用自带的“all.mml.bin”甚至利用命令$javac -XMutator:ALL MyFile.java生成更多的变异体,这个步骤是一个optional的一步,这一步在现实中可以用于对MAJOR的变异算子进行复写或者选择,因项目和个人选择而异。
targetOp{
// Define the replacements for ROR
BIN(>)->{>=,!=,FALSE};
BIN(<)->{<=,!=,FALSE};
BIN(>=)->{>,==,TRUE};
BIN(<=)->{<,==,TRUE};
BIN(==)->{<=,>=,FALSE,LHS,RHS};
BIN(!=)->{<,>,TRUE,LHS,RHS};
// Define the replacements for COR
BIN(&&)->{==,LHS,RHS,FALSE};
BIN(||)->{!=,LHS,RHS,TRUE};
// Define the type of statement that STD should delete
DEL(RETURN);
// Enable the STD, COR, and ROR mutation operators
STD;
COR;
ROR;
}
// Call the defined operator group for the target method
targetOp<"BubbleSort::BubbleSort(int[])">;
之后利用如下命令
$ mmlc BubbleSort.mml BubbleSort.mml.bin
生成编译好的文件。
4.生成变异体
javac -XMutator=BubbleSort.mml.bin -d bin BubbleSort.java
可以从mutants.log文件中读取变异体生成的结果
1:ROR:<(int,int):!=(int,int):BubbleSort@BubbleSort(int[]):6:i < arr.length - 1 |==> i != arr.length - 1
2:ROR:<(int,int):<=(int,int):BubbleSort@BubbleSort(int[]):6:i < arr.length - 1 |==> i <= arr.length - 1
3:ROR:<(int,int):FALSE(int,int):BubbleSort@BubbleSort(int[]):6:i < arr.length - 1 |==> false
如果你想要查看代码,你可以用
$javac -J-Dmajor.export.mutants=true -XMutator:ALL MyFile.java
导出所有的变异体;
5.执行变异体
执行变异体要使用ant,方便起见,我们按照他的目录格式创建文档
BubbleSort -- ant -- src -- BubbleSort.java
-- test -- testBubbleSort.java
-- build.xml
-- run.sh
src:放入你的待测代码
test:放入你的junit代码
build.xml ant的build配置文件,建议你不要随便修改它。
run.sh 用来执行ant compile以及后续过程的一个脚本文件
你可以利用$MAJOR_HOME\example\ant\build.xml 以及同目录下的run.sh的文件;
【请注意,如果你出现了错误,80%的错误都出在这一步;几乎都是因为你的.java和test.java文件没有放对位置,如果你的.java和test.java文件是在同一个package里面,请自行建一个package文件夹套在外面,并且保证你的package之类的名字都写对】
你只需修改第一行<project name="Triangle" default="compile" basedir=".">
将name改成你的项目名,对本示例而言是BubbleSort, 剩下的不要改。
在build.xml中,援引example的例子,下列三个target最重要,不要随便改动;
<!-- Target to compile the project -->
<target name="compile" depends="init" description="Compile">
<javac includeantruntime="true"
srcdir="src"
destdir="bin"
debug="yes"
fork="yes"
executable="${major}">
<compilerarg value="${mutator}"/>
</javac>
</target>
<!-- Target to compile the test suite -->
<target name="compile.tests" depends="compile" description="Compile all tests">
<javac includeantruntime="true"
srcdir="test"
destdir="bin"
debug="yes">
</javac>
</target>
<!-- The adapted mutation test target -->
<target name="mutation.test" description="Run mutation analysis for all unit test cases">
<echo message="Running mutation analysis ..."/>
<junit printsummary="false"
showoutput="false"
mutationAnalysis="true"
resultFile="results.csv"
killDetailsFile="killed.csv">
<classpath path="bin"/>
<batchtest fork="false">
<fileset dir="test">
<include name="**/*Test*.java"/>
</fileset>
</batchtest>
</junit>
</target>
执行run.sh
会得到类似于如下的report
mutation.test:
[echo] Running mutation analysis ...
[junit] MAJOR: Mutation analysis enabled
[junit] MAJOR: ------------------------------------------------------------
[junit] MAJOR: Run 1 ordered test to verify independence
[junit] MAJOR: ------------------------------------------------------------
[junit] MAJOR: Preprocessing time: 0.07 seconds
[junit] MAJOR: ------------------------------------------------------------
[junit] MAJOR: Mutants generated: 35
[junit] MAJOR: Mutants covered: 35 (100.00%)
[junit] MAJOR: ------------------------------------------------------------
[junit] MAJOR: Export test map to testMap.csv
[junit] MAJOR: ------------------------------------------------------------
[junit] MAJOR: Run mutation analysis with 1 individual test
[junit] MAJOR: ------------------------------------------------------------
[junit] MAJOR: 1/1 - BubbleSortTest (14ms / 35):
[junit] MAJOR: 250 (28 / 35 / 35) -> AVG-RTPM: 7ms
[junit] MAJOR: Mutants killed / live: 28 (18-10-0) / 7
[junit] MAJOR: ------------------------------------------------------------
[junit] MAJOR: Summary:
[junit] MAJOR:
[junit] MAJOR: Analysis time: 0.3 seconds
[junit] MAJOR: Mutation score: 80.00% (80.00%)
[junit] MAJOR: Mutants killed / live: 28 (18-10-0) / 7
[junit] MAJOR: Mutant executions: 35
[junit] MAJOR: ------------------------------------------------------------
[junit] MAJOR: Export summary of results to summary.csv
[junit] MAJOR: Export run-time results to results.csv
[junit] MAJOR: Export mutant kill details to killed.csv
当然,如果你现在执行成功了,你就被允许对build.xml进行魔改了;
一些Major-Ant的新功能
你可以尝试使用更多的功能;
【如果你出现了如下错误】
1.我的mutants covered = 0
一个变异体都没有杀死,
要么是你写出了惊世骇俗的测试用例【显然很难】
要么是你的mutation.log在ant compile tests过程中遭到了覆盖;
要么是你的两个.java文件的package出了错,导致编译失败;
要么是你魔改了你的build.xml,或者你的.java命名不带Test,或者.java位置放的不对,导致找文件都没找到;
请你将run.sh的每一步分别来debug;
2.如果你的Java文件不在major的路径下, 不要忘记做一下修改:
run.sh中的:
MAJOR_HOME="../../" 改为 MAJOR_HOME="MAJOR_PATH"
还要修改 build.xml 文件中的 major 属性:
<property name="major" value="../../bin/javac"/> 改为
<property name="major" value="MAJOR_PATH/bin/javac"/>
MAJOR_PATH按照你的实际情况调整;
网友评论