克拉拉(Klara)是一种基于SMT(Z3)求解器的静态分析工具,可自动生成测试用例,具有强大的AST级别推理系统。 Klara将将Python文件作为输入,并以Pytest格式生成相应的测试文件,以覆盖所有返回值。例如,在文件test.py中以下功能
def triangle ( x : int , y : int , z : int ) -> str :
if x == y == z :
return "Equilateral triangle"
elif x == y or y == z or x == z :
return "Isosceles triangle"
else :
return "Scalene triangle"会生成
import test
def test_triangle_0 ():
assert test . triangle ( 0 , 0 , 0 ) == 'Equilateral triangle'
assert test . triangle ( 0 , 0 , 1 ) == 'Isosceles triangle'
assert test . triangle ( 2 , 0 , 1 ) == 'Scalene triangle'请参阅https://klara-py.readthedocs.io,请参见Klara的文档。
注意:克拉拉仍处于早期实验阶段,显着的缺失功能是循环,理解,模块导入,异常等等。请参阅完整列表的限制。它可能不会在现实世界项目上运行,因此最好挑选一些有趣的功能来生成相应的测试用例。
可以通过使用以下方式通过pip工具安装Klara
pip install klara
我们可以在任何python源文件上调用klara ,并且它将生成相应的pytest测试文件。
$ cat source.py
def foo(x: int, y: int, z: str):
if x + y > 2:
return x + y + 12
elif x < y:
return x + y
elif (z + " me " ) == " some " :
return z + " thing "
else:
return x - y
$ klara source.py
$ cat test_source.py
import contract_test
def test_foo_0 ():
assert contract_test.foo(0, 3, '' ) == 15
assert contract_test.foo(0, 1, '' ) == 1
assert contract_test.foo(0, 0, ' so ' ) == ' sothing '
assert contract_test.foo(0, 0, '' ) == 0请咨询快速启动手册以获取更多示例和指导。要将其用作静态分析库,请转到推理。
克拉拉(Klara)在AST级别上工作,并且不会以任何方式执行用户代码,这与使用Crosshair和Pynguin这样的类似工具相比是一个非常重要的差异,该工具使用Consecolic符号执行,该执行需要用户代码执行,这可能会导致不必要的副作用。克拉拉(Klara)在AST级别上工作,与使用控制流程图(CFG),静态单分配(SSA),使用-DEF链等的数据流分析相结合,以构建一个强大的Python推断系统,该系统利用Z3-解决方案来解决约束解决方案解决和路径可行性检查。因此,Klara能够在Typed_ast的帮助下在Python2/3源代码上操作。要指定源代码在Python 2中,请通过-py 2参数。默认情况下是Python 3。
克拉拉(Klara)也可以用作静态分析工具,允许用户定义自定义规则以识别编程错误,错误或执行编码标准。借助SMT求解器支持,分析将更加准确,并大大减少假阳性情况。例如
import klara
tree = klara . parse ( """
def foo(v1: int):
if v1 > 4:
if v1 < 3:
z = 1
else:
z = 2
else:
z = 3
s = z
""" )
with klara . MANAGER . initialize_z3_var_from_func ( tree . body [ 0 ]):
print ( list ( tree . body [ 0 ]. body [ - 1 ]. value . infer ()))将打印出来:
[2, 3]
因为z = 1由于v1 > 4 ,而v1 < 3是不满意的
推理系统体系结构和API在很大程度上受到了Astation库的启发,这是Pylint使用的静态推理库。
克拉拉(Klara)利用推理系统来生成测试用例,换句话说,它为函数的所有可能返回值生成了测试用例,而不是为函数的所有控制路径生成测试用例。
为了说明这一点,请考虑以下功能,在第3行中divide by zero漏洞
def foo ( v1 : int , v2 : float ):
if v1 > 10000 :
s = v1 / 0 # unused statement
if v1 > v2 :
s = v1
else :
s = v2
return s克拉拉将在下面生成测试输入
import contract_test
def test_foo_0 ():
assert contract_test . foo ( 0 , - 1.0 ) == 0
assert contract_test . foo ( 0 , 0.0 ) == 0.0它不会生成输入v1 > 10000 ,因此测试案例将无法找到异常。这是因为第3行的s在返回值中未使用。
如果我们将第二个IF语句修改为elif ,我们将能够在第3行中返回[s] {。title-ref},Klara将生成涵盖v1 > 10000情况的测试输入。
这是与现在可用的其他自动测试用例生成的重要区别,因为仅通过生成返回值的测试用例,我们就可以生成最小的测试用例,并且更容易自定义Klara如何覆盖该功能。
例如,假设我们正在构成一个复杂的系统
def main ( number : int , cm : int , dc : int , wn : int ):
mc = 0
if wn > 2 :
if number > 2 and number > 2 or number > 2 :
if number > 0 :
if wn > 2 or wn > 2 :
mc = 2
else :
mc = 5
else :
mc = 100
else :
mc = 1
nnn = number * cm
if cm <= 4 :
num_incr = 4
else :
num_incr = cm
n_num_incr = nnn / num_incr
nnn_left = dc * num_incr * ( n_num_incr / 2 + n_num_incr % 2 )
nnn_right = nnn - nnn_left
is_flag = nnn_right
if is_flag :
cell = Component ( nnn_right , options = [ mc ])
else :
cell = Component ( nnn_right )
return cell我们尚不清楚有多少可能的返回值。但是我们可以利用克拉拉立即生成输入,以下是生成的测试
import contract_test
def test_main_0 ():
assert contract_test . main ( 2 , 4 , 1 , 3 ) is not None
assert contract_test . main ( 2 , 4 , - 1 , 6 ) is not None
assert contract_test . main ( 2 , 4 , 1 , 4 ) is not None
assert contract_test . main ( - 2 , 4 , 3 , 4 ) is not None
assert contract_test . main ( - 1 , - 1 , - 1 , 2 ) is not None
assert contract_test . main ( 0 , 0 , 0 , 3 ) is not None
assert contract_test . main ( 0 , 0 , 0 , 6 ) is not None
assert contract_test . main ( 0 , 0 , 0 , 4 ) is not None
assert contract_test . main ( - 2 , 0 , 0 , 4 ) is not None
assert contract_test . main ( 0 , 0 , 0 , 0 ) is not None以上生成的10个总结果,这是nnn_right的产物,具有2种可能性,具有5 mc可能性。
假设10个测试输入太多了,我们已经确定要测试的options Component是多余的,我们可以使用Klara的自定义插件来选择性地确定在测试生成中要忽略的部分。转到自定义覆盖策略以获取更多信息。
设置插件后,Klara将生成以下测试
import contract_test
def test_main_0 ():
assert contract_test . main ( 1 , 3 , 0 , 0 ) is not None
assert contract_test . main ( 0 , 0 , 0 , 0 ) is not None这只有2个组合nnn_right
由于Klara无法动态执行代码,因此它将提供扩展名来指定如何推断特定的AST节点或用户定义的类型以使Klara“ Smarter”。它在扩展,扩展用户类型和自定义覆盖策略时进行了描述。
我们使用诗歌来管理依赖关系。安装诗歌后,运行:
$ poetry shell
$ poetry install
要运行测试案例,请执行:
$ poetry run pytest test
该项目是根据GNU较少的通用公共许可证的条款许可的。