克拉拉(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較少的通用公共許可證的條款許可的。