一、什么是变异测试
基于网上冲浪,现有变异测试有2两种阐述:
- 一是针对case的变异;
- 二是针对代码的变异;
无论是哪种 都是通过某种规则对case/代码进行变更,针对该case/代码产生N个变异体,如+ -互换、*/互换…
这里我将利用语法树实现~
二、认识语法树AST
- 百度百科:https://baike.baidu.com/item/%E8%AF%AD%E6%B3%95%E6%A0%91/7031301?fr=aladdin
- 说人话:将代码以树的形式呈现。
我们可以在遍历语法树的过程中按照约定的形式更改树的结构,从而实现修改代码~
PS:由于目前用的技术栈是Go,以下展开说明皆是针对Go而言。
三、具体实践
3.1 认识go/ast包
3.2 语法树的遍历
方法一、func Walk(v Visitor, node Node)
方法二、func Inspect(node Node, f func(Node) bool)
简要说明一下两者异同:两者都是基于深度优先遍历,且后者是前者的更简要实现~
PS:Walk方法是基于访问者模式实现
贴下关键代码:
//创建fileset原文件集合,用于保存token信息
fset := token.NewFileSet()
//将文件解析为AST
parsedFile, err := parser.ParseFile(fset, ...)
//方法一:
//1.遍历
ast.Walk(file, parsedFile)
//2.实现Visit接口
func (f *File) Visit(node ast.Node) ast.Visitor {
switch n := node.(type) {
case *ast.ExprStmt://表达式语句
...
case *ast.BlockStmt://表示{}
...
}
return f
}
//方法二:
ast.Inspect(f, func(n ast.Node) bool {
switch x := n.(type) {
case *ast.AssignStmt: //赋值语句
...
}
return true
}
3.3 修改语法树Node
遍历到某节点时,修改该节点Noe,示例如下:
如果是赋值语句的操作符,则更改该节点Tok