Klaraは、強力なASTレベル推論システムを備えたSMT(Z3)ソルバーに基づいて、テストケースを自動生成するための静的分析ツールです。 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のドキュメントを参照してください
注:Klaraはまだ初期の実験段階にあり、注目に値する機能はループ、理解、モジュールのインポート、例外などです。完全なリストについては、制限を参照してください。おそらく実世界のプロジェクトでは実行されないので、対応するテストケースを生成するためにいくつかの興味深い機能を選び出すのが最善です。
Klaraは、以下を使用してpipツールを介してインストールできます。
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などの同様のツールと比較して非常に重要な違いです。 KlaraはASTレベルで動作し、コントロールフローグラフ(CFG)、静的シングル割り当て(SSA)、使用-DEFチェーンなどを利用するデータフロー分析と組み合わせて、制約の解決とパスの実現可能性チェックのためにZ3ソルバーを活用する強力なPython推論システムを構築します。このため、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は、Pylintが使用する静的な推論ライブラリであるAstroidに主に触発されています。
Klaraは推論システムを利用してテストケースを生成します。つまり、関数のすべての制御パスのテストケースを生成する代わりに、関数のすべての可能な返品値のテストケースを生成します。
ポイントを説明するには、以下の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 sKlaraは以下のテスト入力を生成します
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が返品値で使用されていないためです。
2番目のIFステートメントをelifに変更すると、3行目で[s] {。タイトル-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可能な返品値がいくつあるかはすぐには明らかではありません。しかし、Klaraを利用して入力を即座に生成することができます。以下は生成されたテストです
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の結果が生成されました。これは、2つの可能性を持つnnn_rightの積と5つの可能性を持つmcです。
10個のテスト入力が多すぎて、 Componentへのoptions引数がテストするのが冗長であると判断したとします。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これは、 nnn_rightの2つの組み合わせです
Klaraはコードを動的に実行できないため、特定のASTノードまたはユーザー定義タイプを推測してKlaraを「スマート」にする方法を指定する拡張機能を提供します。ユーザータイプを拡張、拡張、カスタマイズカバレッジ戦略について説明しています。
詩を使用して依存関係を管理します。詩がインストールされた後、実行してください:
$ poetry shell
$ poetry install
テストケースを実行するには、次のことを行います。
$ poetry run pytest test
このプロジェクトは、GNU以下の一般公開ライセンスの条件に基づいてライセンスされています。