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 수준에서 작동하며 어떤 방식 으로든 사용자 코드를 실행하지 않습니다. 이는 원치 않는 부작용을 유발할 수있는 사용자 코드 실행이 필요한 Concolic Symbolic Execution을 사용하는 Crosshair 및 Pynguin과 비슷한 도구와 비교하여 매우 중요한 차이입니다. Klara는 AST 레벨에서 작동하며 CFG (Control Flow Graph), 정적 단일 할당 (SSA), 사용 DEF 체인 등을 사용하는 데이터 흐름 분석과 결합하여 Z3-Solver를 제한을 해결하고 경로 타당성 검사를 활용하는 강력한 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]
v1 > 4 로 인해 z = 1 불가능하고 v1 < 3 불만족 스럽기 때문에
추론 시스템 아키텍처 및 API는 Pylint에서 사용하는 정적 추론 라이브러리 인 Astroid에서 영감을 얻었습니다.
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가능한 수익 값이 얼마나 많은지 우리에게 즉시 명확하지 않습니다. 그러나 우리는 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 개의 총 결과가 생성되었으며, 이는 nnn_right 의 산물 인 2 가지 가능성과 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 Lesser General Public License의 조건에 따라 라이센스가 부여됩니다.