Klara เป็นเครื่องมือวิเคราะห์แบบคงที่ในการสร้างกรณีทดสอบโดยอัตโนมัติโดยใช้ตัวแก้ SMT (Z3) ด้วยระบบการอนุมานระดับ AST ที่ทรงพลัง Klara จะใช้ไฟล์ Python เป็นอินพุตและสร้างไฟล์ทดสอบที่สอดคล้องกันในรูปแบบ pytest ซึ่งพยายามครอบคลุมค่าคืนทั้งหมด ตัวอย่างเช่นฟังก์ชั่นต่อไปนี้ใน file 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'ดูเอกสารของ Klara ได้ที่ https://klara-py.readthedocs.io
หมายเหตุ : Klara ยังอยู่ในช่วงระยะแรกการทดลองคุณลักษณะที่ขาดหายไปที่น่าสังเกตคือลูป, ความเข้าใจ, การนำเข้าโมดูล, ข้อยกเว้นและอื่น ๆ อีกมากมาย ดูข้อ จำกัด สำหรับรายการทั้งหมด มันอาจจะไม่ทำงานในโครงการในโลกแห่งความเป็นจริงดังนั้นจึงเป็นการดีที่สุดที่จะเลือกใช้ฟังก์ชั่นที่น่าสนใจบางอย่างเพื่อสร้างกรณีทดสอบที่เกี่ยวข้อง
Klara สามารถติดตั้งผ่านเครื่องมือ pip โดยใช้:
pip install klara
เราสามารถเรียก 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), ห่วงโซ่การใช้งาน, ฯลฯ ... เพื่อสร้างระบบการอนุมาน Python ที่ทรงพลังซึ่งใช้ประโยชน์จาก Z3-Solver ด้วยเหตุนี้ Klara จึงสามารถใช้งานได้ทั้งในซอร์สโค้ด Python2/3 ด้วยความช่วยเหลือของ Typed_ast ในการระบุซอร์สโค้ดอยู่ใน Python 2 ให้ผ่านอาร์กิวเมนต์ -py 2 มันคือ Python 3 โดยค่าเริ่มต้น
Klara ยังสามารถใช้เป็นเครื่องมือวิเคราะห์แบบคงที่อนุญาตให้ผู้ใช้กำหนดกฎที่กำหนดเองเพื่อระบุข้อผิดพลาดการเขียนโปรแกรมข้อผิดพลาดหรือการบังคับใช้มาตรฐานการเข้ารหัส ด้วยการสนับสนุน SMT Solver การวิเคราะห์จะมีความแม่นยำมากขึ้นและลดกรณีที่ผิดพลาดได้อย่างมาก ตัวอย่างเช่น
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 ได้รับแรงบันดาลใจจาก Astroid ส่วนใหญ่เป็นไลบรารีการอนุมานแบบคงที่ที่ Pylint ใช้
Klara ใช้ระบบการอนุมานเพื่อสร้างกรณีทดสอบกล่าวอีกนัยหนึ่งมัน สร้างกรณีทดสอบสำหรับค่าคืนที่เป็นไปได้ทั้งหมดของฟังก์ชัน แทนที่จะสร้างกรณีทดสอบสำหรับเส้นทางการควบคุมทั้งหมดของฟังก์ชัน
เพื่อแสดงให้เห็นถึงจุดพิจารณาฟังก์ชั่นด้านล่างโดย divide by zero ด้วยช่องโหว่เป็นศูนย์ที่บรรทัดที่ 3
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 ดังนั้นกรณีทดสอบจะไม่สามารถหาข้อยกเว้นได้ นี่เป็นเพราะ s ที่บรรทัดที่ 3 ไม่ได้ใช้ในค่าผลตอบแทน
หากเราแก้ไขคำสั่งที่สองหากเป็น elif ซึ่งเราจะสามารถส่งคืน [s] {. title-ref} ที่บรรทัดที่ 3 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 ประการและ mc ซึ่งมีความเป็นไปได้ 5 ประการ
สมมติว่าอินพุตการทดสอบ 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 'ฉลาดขึ้น' มันอธิบายไว้ในการขยายขยายประเภทผู้ใช้และปรับแต่งกลยุทธ์การครอบคลุม
เราใช้บทกวีเพื่อจัดการการพึ่งพา หลังจากติดตั้งบทกวีแล้วให้เรียกใช้:
$ poetry shell
$ poetry install
ในการเรียกใช้กรณีทดสอบทำ:
$ poetry run pytest test
โครงการนี้ได้รับใบอนุญาตภายใต้ข้อกำหนดของใบอนุญาตสาธารณะ GNU Lesser ทั่วไป