คุณกำลังใช้pytest
งานซึ่งจะช่วยให้คุณมีตัวเลือกมากมายในการโต้ตอบกับการทดสอบที่ล้มเหลว มันทำให้คุณมีตัวเลือกบรรทัดคำสั่งและตะขอหลายอย่างเพื่อให้เป็นไปได้ ฉันจะอธิบายวิธีใช้แต่ละจุดที่คุณสามารถปรับแต่งเพื่อให้เหมาะกับความต้องการในการดีบักเฉพาะของคุณ
ฉันจะไปยังตัวเลือกที่แปลกใหม่มากขึ้นซึ่งจะช่วยให้คุณสามารถข้ามการยืนยันที่เฉพาะเจาะจงทั้งหมดถ้าคุณรู้สึกว่าคุณต้อง
จัดการข้อยกเว้นไม่ยืนยัน
โปรดทราบว่าการทดสอบที่ล้มเหลวจะไม่หยุดโดยปกติ pytest เฉพาะในกรณีที่คุณเปิดใช้งานการแจ้งอย่างชัดเจนให้ออกหลังจากความล้มเหลวจำนวนหนึ่ง นอกจากนี้การทดสอบล้มเหลวเนื่องจากมีการยกข้อยกเว้น assert
เพิ่มขึ้นAssertionError
แต่นั่นไม่ใช่ข้อยกเว้นเพียงอย่างเดียวที่จะทำให้การทดสอบล้มเหลว! assert
คุณต้องการที่จะควบคุมวิธีการข้อยกเว้นได้รับการจัดการไม่เปลี่ยนแปลง
อย่างไรก็ตามการยืนยันที่ล้มเหลวจะสิ้นสุดการทดสอบแต่ละรายการ นั่นเป็นเพราะเมื่อมีการยกข้อยกเว้นนอกtry...except
บล็อก Python จะคลายเฟรมฟังก์ชันปัจจุบันและจะไม่มีการย้อนกลับไป
ฉันไม่คิดว่านั่นคือสิ่งที่คุณต้องการตัดสินโดยคำอธิบายของคุณเกี่ยว_assertCustom()
กับความพยายามในการยืนยันอีกครั้ง แต่ฉันจะพูดถึงตัวเลือกของคุณต่อไป
การดีบักโพสต์ชันสูตรใน pytest ด้วย pdb
สำหรับตัวเลือกต่าง ๆ เพื่อจัดการกับความล้มเหลวในดีบักเกอร์ฉันจะเริ่มต้นด้วย--pdb
สวิตช์บรรทัดคำสั่งซึ่งจะเปิดพร้อมท์การดีบักมาตรฐานเมื่อการทดสอบล้มเหลว
$ mkdir demo
$ touch demo/__init__.py
$ cat << EOF > demo/test_foo.py
> def test_ham():
> assert 42 == 17
> def test_spam():
> int("Vikings")
> EOF
$ pytest demo/test_foo.py --pdb
[ ... ]
test_foo.py:2: AssertionError
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> entering PDB >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
> /.../demo/test_foo.py(2)test_ham()
-> assert 42 == 17
(Pdb) q
Exit: Quitting debugger
[ ... ]
ด้วยสวิตช์นี้เมื่อการทดสอบล้มเหลว pytest เริ่มชันสูตรศพเซสชั่นการแก้จุดบกพร่อง นี่คือสิ่งที่คุณต้องการอย่างแท้จริง เพื่อหยุดโค้ดที่จุดที่ทำการทดสอบที่ล้มเหลวและเปิดดีบักเกอร์เพื่อดูสถานะการทดสอบของคุณ คุณสามารถโต้ตอบกับตัวแปรท้องถิ่นของการทดสอบ, globals และ localals และ globals ของทุกเฟรมในสแต็ก
ที่นี่ pytest ช่วยให้คุณควบคุมได้อย่างสมบูรณ์ว่าจะออกจากจุดนี้หรือไม่: ถ้าคุณใช้q
คำสั่ง quit จากนั้น pytest จะออกจากการรันด้วยการใช้c
เพื่อดำเนินการต่อจะส่งคืนการควบคุมไปยัง pytest และทำการทดสอบครั้งต่อไป
ใช้ดีบักเกอร์สำรอง
คุณไม่ได้ผูกพันกับpdb
ดีบักเกอร์สำหรับสิ่งนี้ คุณสามารถตั้งค่าดีบักเกอร์ที่แตกต่างด้วย--pdbcls
สวิตช์ การใช้งานที่pdb.Pdb()
เข้ากันได้ใด ๆจะทำงานได้รวมถึงการใช้งานดีบักเกอร์ IPythonหรือดีบั๊ก Python อื่น ๆ ส่วนใหญ่ (ตัวดีบัก pudbต้องการ-s
สวิตช์ที่ใช้หรือปลั๊กอินพิเศษ ) สวิตช์ใช้โมดูลและคลาสเช่นpudb
คุณสามารถใช้:
$ pytest -s --pdb --pdbcls=pudb.debugger:Debugger
คุณสามารถใช้คุณสมบัตินี้ในการเขียนระดับกระดาษห่อของคุณเองรอบPdb
ที่เพียงแค่ส่งกลับทันทีถ้าล้มเหลวที่เฉพาะเจาะจงไม่ได้เป็นสิ่งที่คุณมีความสนใจใน. pytest
ใช้Pdb()
เหมือนpdb.post_mortem()
ไม่ :
p = Pdb()
p.reset()
p.interaction(None, t)
นี่t
คือวัตถุย้อนกลับ เมื่อp.interaction(None, t)
ส่งคืนให้pytest
ดำเนินการทดสอบต่อไปเว้นแต่ p.quitting
จะตั้งค่าเป็นTrue
(ที่จุด pytest แล้วออก)
นี่คือตัวอย่างการใช้งานที่พิมพ์ออกมาว่าเราปฏิเสธที่จะแก้ไขข้อบกพร่องและส่งคืนทันทียกเว้นกรณีที่การทดสอบยกขึ้นValueError
บันทึกเป็นdemo/custom_pdb.py
:
import pdb, sys
class CustomPdb(pdb.Pdb):
def interaction(self, frame, traceback):
if sys.last_type is not None and not issubclass(sys.last_type, ValueError):
print("Sorry, not interested in this failure")
return
return super().interaction(frame, traceback)
เมื่อฉันใช้สิ่งนี้กับการสาธิตด้านบนนี่คือผลลัพธ์ (อีกครั้งเพื่อความกะทัดรัด):
$ pytest test_foo.py -s --pdb --pdbcls=demo.custom_pdb:CustomPdb
[ ... ]
def test_ham():
> assert 42 == 17
E assert 42 == 17
test_foo.py:2: AssertionError
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> entering PDB >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Sorry, not interested in this failure
F
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> traceback >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
def test_spam():
> int("Vikings")
E ValueError: invalid literal for int() with base 10: 'Vikings'
test_foo.py:4: ValueError
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> entering PDB >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
> /.../test_foo.py(4)test_spam()
-> int("Vikings")
(Pdb)
วิปัสสนาข้างต้นsys.last_type
เพื่อตรวจสอบว่าความล้มเหลวคือ 'น่าสนใจ'
อย่างไรก็ตามฉันไม่สามารถแนะนำตัวเลือกนี้ได้นอกเสียจากว่าคุณต้องการเขียนดีบักเกอร์ของคุณเองโดยใช้ tkInter หรือสิ่งที่คล้ายกัน โปรดทราบว่านั่นเป็นงานที่ยิ่งใหญ่
การกรองความล้มเหลว; เลือกและเลือกเวลาที่จะเปิดดีบักเกอร์
ระดับถัดไปคือการดีบัก pytest และการโต้ตอบการขอ ; สิ่งเหล่านี้เป็นจุดเชื่อมโยงสำหรับการปรับแต่งพฤติกรรมเพื่อแทนที่หรือปรับปรุงวิธีการจัดการโดยปกติของ pytest เช่นการจัดการข้อยกเว้นหรือการป้อนดีบักเกอร์ผ่านpdb.set_trace()
หรือbreakpoint()
(Python 3.7 หรือใหม่กว่า)
การนำไปใช้ภายในของ hook นี้รับผิดชอบการพิมพ์>>> entering PDB >>>
แบนเนอร์ด้านบนด้วยดังนั้นการใช้ hook นี้เพื่อป้องกันไม่ให้ดีบักเกอร์ทำงานหมายความว่าคุณจะไม่เห็นผลลัพธ์นี้เลย คุณสามารถมีตะขอของคุณเองจากนั้นมอบหมายให้ตะขอเดิมเมื่อความล้มเหลวในการทดสอบนั้น 'น่าสนใจ' และดังนั้นความล้มเหลวในการทดสอบตัวกรองจึงไม่ขึ้นอยู่กับดีบักเกอร์ที่คุณใช้! คุณสามารถเข้าถึงการดำเนินงานภายในโดยการเข้าถึงโดยใช้ชื่อ ; ปลั๊กอิน hook ภายในสำหรับชื่อpdbinvoke
นี้ ในการป้องกันไม่ให้ทำงานคุณจำเป็นต้องยกเลิกการลงทะเบียนแต่บันทึกการอ้างอิงเราสามารถเรียกมันได้โดยตรงตามต้องการ
นี่คือตัวอย่างการใช้งานของ hook เช่น; คุณสามารถวางสิ่งนี้ลงในปลั๊กอินตำแหน่งใดก็ได้ที่โหลดจาก ; ฉันใส่ไว้ในdemo/conftest.py
:
import pytest
@pytest.hookimpl(trylast=True)
def pytest_configure(config):
# unregister returns the unregistered plugin
pdbinvoke = config.pluginmanager.unregister(name="pdbinvoke")
if pdbinvoke is None:
# no --pdb switch used, no debugging requested
return
# get the terminalreporter too, to write to the console
tr = config.pluginmanager.getplugin("terminalreporter")
# create or own plugin
plugin = ExceptionFilter(pdbinvoke, tr)
# register our plugin, pytest will then start calling our plugin hooks
config.pluginmanager.register(plugin, "exception_filter")
class ExceptionFilter:
def __init__(self, pdbinvoke, terminalreporter):
# provide the same functionality as pdbinvoke
self.pytest_internalerror = pdbinvoke.pytest_internalerror
self.orig_exception_interact = pdbinvoke.pytest_exception_interact
self.tr = terminalreporter
def pytest_exception_interact(self, node, call, report):
if not call.excinfo. errisinstance(ValueError):
self.tr.write_line("Sorry, not interested!")
return
return self.orig_exception_interact(node, call, report)
ปลั๊กอินข้างต้นใช้ภายในTerminalReporter
ปลั๊กอินที่จะเขียนออกเส้นไปยังสถานี; สิ่งนี้ทำให้ตัวล้างเอาต์พุตเมื่อใช้รูปแบบสถานะการทดสอบขนาดกะทัดรัดเริ่มต้นและช่วยให้คุณสามารถเขียนสิ่งต่าง ๆ ไปยังเทอร์มินัลได้แม้จะเปิดใช้งานการบันทึกเอาต์พุต
ตัวอย่างจะลงทะเบียนวัตถุปลั๊กอินด้วยpytest_exception_interact
hook ผ่านตะขออื่นpytest_configure()
แต่ให้แน่ใจว่ามันทำงานช้าพอ (ใช้@pytest.hookimpl(trylast=True)
) เพื่อที่จะสามารถยกเลิกการลงทะเบียนpdbinvoke
ปลั๊กอินภายใน เมื่อเบ็ดเรียกว่าตัวอย่างทดสอบกับcall.exceptinfo
วัตถุ ; คุณสามารถตรวจสอบโหนดหรือรายงานได้เช่นกัน
เมื่อโค้ดตัวอย่างข้างต้นเข้าแทนที่ความล้มเหลวในdemo/conftest.py
การtest_ham
ทดสอบจะถูกละเว้นเฉพาะtest_spam
ความล้มเหลวในการทดสอบซึ่งเพิ่มขึ้นValueError
ส่งผลให้เกิดการเปิดพร้อมท์การดีบัก:
$ pytest demo/test_foo.py --pdb
[ ... ]
demo/test_foo.py F
Sorry, not interested!
demo/test_foo.py F
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> traceback >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
def test_spam():
> int("Vikings")
E ValueError: invalid literal for int() with base 10: 'Vikings'
demo/test_foo.py:4: ValueError
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> entering PDB >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
> /.../demo/test_foo.py(4)test_spam()
-> int("Vikings")
(Pdb)
หากต้องการปรับใหม่อีกครั้งวิธีการข้างต้นมีข้อดีเพิ่มเติมที่คุณสามารถรวมเข้ากับดีบักเกอร์ที่ทำงานกับ pytestรวมถึง pudb หรือดีบักเกอร์ IPython:
$ pytest demo/test_foo.py --pdb --pdbcls=IPython.core.debugger:Pdb
[ ... ]
demo/test_foo.py F
Sorry, not interested!
demo/test_foo.py F
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> traceback >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
def test_spam():
> int("Vikings")
E ValueError: invalid literal for int() with base 10: 'Vikings'
demo/test_foo.py:4: ValueError
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> entering PDB >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
> /.../demo/test_foo.py(4)test_spam()
1 def test_ham():
2 assert 42 == 17
3 def test_spam():
----> 4 int("Vikings")
ipdb>
นอกจากนี้ยังมีบริบทอื่น ๆ อีกมากมายเกี่ยวกับการทดสอบที่เรียกใช้ (ผ่านการnode
โต้แย้ง) และการเข้าถึงโดยตรงไปยังข้อยกเว้นที่เกิดขึ้น (ผ่านcall.excinfo
ExceptionInfo
อินสแตนซ์)
โปรดทราบว่าปลั๊กอินดีบักเกอร์ pytest เฉพาะ (เช่นpytest-pudb
หรือpytest-pycharm
) ลงทะเบียนpytest_exception_interact
hooksp ของตนเอง การใช้งานที่สมบูรณ์ยิ่งขึ้นจะต้องวนซ้ำปลั๊กอินทั้งหมดใน plugin-manager เพื่อแทนที่ปลั๊กอินใด ๆ โดยอัตโนมัติโดยใช้config.pluginmanager.list_name_plugin
และhasattr()
ทดสอบแต่ละปลั๊กอิน
ทำให้ความล้มเหลวหายไปโดยสิ้นเชิง
แม้ว่าสิ่งนี้จะช่วยให้คุณสามารถควบคุมการดีบักการทดสอบที่ล้มเหลวได้อย่างสมบูรณ์ แต่ก็ยังทำให้การทดสอบนั้นล้มเหลวแม้ว่าคุณจะเลือกที่จะไม่เปิดตัวดีบั๊กสำหรับการทดสอบที่ได้รับก็ตาม pytest_runtest_call()
หากคุณต้องการที่จะทำให้ความล้มเหลวหายไปโดยสิ้นเชิงคุณสามารถทำให้การใช้ตะขอที่แตกต่างกัน
เมื่อ pytest ทำการทดสอบมันจะทำการทดสอบผ่านทาง hook ด้านบนซึ่งคาดว่าจะคืนNone
หรือเพิ่มข้อยกเว้น จากรายงานนี้ถูกสร้างขึ้นเป็นทางเลือกรายการบันทึกถูกสร้างขึ้นและหากการทดสอบล้มเหลวpytest_exception_interact()
เบ็ดดังกล่าวจะถูกเรียกว่า ดังนั้นสิ่งที่คุณต้องทำคือเปลี่ยนสิ่งที่ผลลัพธ์ที่ตะขอนี้ผลิต แทนที่จะเป็นข้อยกเว้นไม่ควรส่งคืนสิ่งใดเลย
วิธีที่ดีที่สุดที่จะทำคือการใช้กระดาษห่อเบ็ด ฮุกห่อไม่จำเป็นต้องทำงานจริง แต่แทนที่จะได้รับโอกาสที่จะแก้ไขสิ่งที่เกิดขึ้นกับผลของตะขอ สิ่งที่คุณต้องทำคือเพิ่มบรรทัด:
outcome = yield
ในตะขอเสื้อคลุมการดำเนินงานและคุณจะได้รับการเข้าถึงผลเบ็ดoutcome.excinfo
รวมทั้งยกเว้นการทดสอบผ่าน แอ็ตทริบิวต์นี้ถูกตั้งค่าเป็น tuple ของ (ชนิด, อินสแตนซ์, การติดตามกลับ) หากข้อยกเว้นถูกยกขึ้นในการทดสอบ อีกวิธีหนึ่งคุณสามารถโทรoutcome.get_result()
และใช้การtry...except
จัดการมาตรฐาน
ดังนั้นคุณจะทำการทดสอบผ่านที่ล้มเหลวได้อย่างไร คุณมี 3 ตัวเลือกพื้นฐาน:
- คุณสามารถทำเครื่องหมายการทดสอบว่าเป็นความล้มเหลวที่คาดไว้โดยการโทร
pytest.xfail()
ใน wrapper
- คุณสามารถทำเครื่องหมายรายการเป็นข้าม
pytest.skip()
ซึ่งอ้างว่าการทดสอบก็ไม่เคยทำงานในสถานที่แรกโดยการเรียก
- คุณสามารถลบข้อยกเว้นโดยใช้
outcome.force_result()
วิธีการ ; ตั้งค่าผลลัพธ์เป็นรายการว่างที่นี่ (หมายถึง: hook ที่ลงทะเบียนไม่ได้ทำอะไรนอกจากNone
) และข้อยกเว้นจะถูกล้างทั้งหมด
สิ่งที่คุณใช้นั้นขึ้นอยู่กับคุณ ตรวจสอบให้แน่ใจว่าได้ตรวจสอบผลลัพธ์สำหรับการทดสอบที่ข้ามและคาดว่าจะล้มเหลวก่อนเนื่องจากคุณไม่จำเป็นต้องจัดการกับกรณีเหล่านั้นราวกับว่าการทดสอบล้มเหลว คุณสามารถเข้าถึงข้อยกเว้นพิเศษเพิ่มตัวเลือกเหล่านี้ผ่านทางและpytest.skip.Exception
pytest.xfail.Exception
ต่อไปนี้เป็นตัวอย่างการใช้งานซึ่งทำเครื่องหมายการทดสอบที่ล้มเหลวซึ่งไม่ได้เพิ่มValueError
ดังที่ถูกข้าม :
import pytest
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_call(item):
outcome = yield
try:
outcome.get_result()
except (pytest.xfail.Exception, pytest.skip.Exception, pytest.exit.Exception):
raise # already xfailed, skipped or explicit exit
except ValueError:
raise # not ignoring
except (pytest.fail.Exception, Exception):
# turn everything else into a skip
pytest.skip("[NOTRUN] ignoring everything but ValueError")
เมื่อใส่ในconftest.py
ผลลัพธ์จะกลายเป็น:
$ pytest -r a demo/test_foo.py
============================= test session starts =============================
platform darwin -- Python 3.8.0, pytest-3.10.0, py-1.7.0, pluggy-0.8.0
rootdir: ..., inifile:
collected 2 items
demo/test_foo.py sF [100%]
=================================== FAILURES ===================================
__________________________________ test_spam ___________________________________
def test_spam():
> int("Vikings")
E ValueError: invalid literal for int() with base 10: 'Vikings'
demo/test_foo.py:4: ValueError
=========================== short test summary info ============================
FAIL demo/test_foo.py::test_spam
SKIP [1] .../demo/conftest.py:12: [NOTRUN] ignoring everything but ValueError
===================== 1 failed, 1 skipped in 0.07 seconds ======================
ฉันใช้-r a
ธงเพื่อให้ชัดเจนยิ่งขึ้นซึ่งtest_ham
ถูกข้ามไปแล้ว
หากคุณแทนที่การpytest.skip()
โทรด้วยpytest.xfail("[XFAIL] ignoring everything but ValueError")
การทดสอบจะถูกทำเครื่องหมายว่าเป็นความล้มเหลวที่คาดไว้:
[ ... ]
XFAIL demo/test_foo.py::test_ham
reason: [XFAIL] ignoring everything but ValueError
[ ... ]
และใช้outcome.force_result([])
เครื่องหมายตามที่ผ่าน:
$ pytest -v demo/test_foo.py # verbose to see individual PASSED entries
[ ... ]
demo/test_foo.py::test_ham PASSED [ 50%]
มันขึ้นอยู่กับคุณว่าคนไหนที่เหมาะกับการใช้งานของคุณมากที่สุด สำหรับskip()
และxfail()
ฉันเลียนแบบรูปแบบข้อความมาตรฐาน (นำหน้าด้วย[NOTRUN]
หรือ[XFAIL]
) แต่คุณมีอิสระที่จะใช้รูปแบบข้อความอื่น ๆ ที่คุณต้องการ
ในทั้งสามกรณี pytest จะไม่เปิดดีบักเกอร์สำหรับการทดสอบที่คุณแก้ไขผลลัพธ์โดยใช้วิธีนี้
การปรับเปลี่ยนข้อความยืนยันแต่ละรายการ
หากคุณต้องการแก้ไขassert
การทดสอบภายในการทดสอบคุณจะตั้งค่าตัวเองสำหรับการทำงานมากขึ้น ใช่มันเป็นไปได้ทางเทคนิคแต่เพียงแค่เขียนรหัสใหม่ที่ Python จะดำเนินการในเวลารวบรวมเท่านั้น
เมื่อคุณใช้pytest
งานจริงสิ่งนี้กำลังดำเนินการอยู่ Pytest ปรับเปลี่ยนassert
งบเพื่อให้คุณได้มากขึ้นเมื่อบริบทอ้างของคุณล้มเหลว ; ดูโพสต์บล็อกนี้สำหรับภาพรวมที่ดีของสิ่งที่จะถูกดำเนินการเช่นเดียวกับรหัสที่มา_pytest/assertion/rewrite.py
โปรดทราบว่าโมดูลนั้นมีความยาวเกิน 1k บรรทัดและต้องการให้คุณเข้าใจว่าโครงสร้างแบบนามธรรมของ Pythonทำงานอย่างไร หากคุณทำเช่นนั้นคุณสามารถปรับแต่งโมดูลนั้นเพื่อเพิ่มการแก้ไขของคุณเองที่นั่นรวมถึงการล้อมรอบassert
ด้วยtry...except AssertionError:
ตัวจัดการ
อย่างไรก็ตามคุณไม่สามารถปิดใช้งานหรือเพิกเฉยการอ้างสิทธิ์ที่เลือกได้เนื่องจากข้อความสั่งที่ตามมาอาจขึ้นอยู่กับสถานะ (การจัดเรียงวัตถุเฉพาะชุดตัวแปร ฯลฯ ) ที่การยืนยันที่ข้ามนั้นมีไว้เพื่อป้องกัน หากการทดสอบการยืนยันที่foo
ไม่ได้None
มีการยืนยันในภายหลังอาศัยfoo.bar
อยู่แล้วคุณก็จะวิ่งเข้าไปที่AttributeError
นั่น ฯลฯ ทำติดเพื่อยกข้อยกเว้นอีกครั้งถ้าคุณจำเป็นต้องไปเส้นทางนี้
ฉันจะไม่เข้าไปดูรายละเอียดเพิ่มเติมเกี่ยวกับการเขียนใหม่asserts
ที่นี่เนื่องจากฉันไม่คิดว่านี่จะเป็นสิ่งที่ควรทำไม่ได้รับปริมาณงานที่เกี่ยวข้อง จุดของความล้มเหลวการยืนยันอยู่แล้ว
โปรดทราบว่าหากคุณต้องการทำสิ่งนี้คุณไม่จำเป็นต้องใช้eval()
(ซึ่งไม่สามารถใช้งานassert
ได้เป็นคำสั่งดังนั้นคุณจะต้องใช้exec()
แทน) และคุณจะไม่ต้องทำการยืนยันสองครั้ง สามารถนำไปสู่ปัญหาหากการแสดงออกที่ใช้ในสถานะการเปลี่ยนแปลงการยืนยัน) คุณต้องฝังast.Assert
โหนดภายในast.Try
โหนดแทนและแนบตัวจัดการยกเว้นที่ใช้ast.Raise
โหนดว่างอีกครั้งยกข้อยกเว้นที่ถูกจับ
การใช้ดีบักเกอร์เพื่อข้ามคำสั่งยืนยัน
งูหลามดีบักจริงช่วยให้คุณสามารถข้ามงบโดยใช้j
/jump
คำสั่ง หากคุณรู้ล่วงหน้าว่าการยืนยันเฉพาะจะล้มเหลวคุณสามารถใช้วิธีนี้เพื่อข้ามมันได้ คุณสามารถเรียกใช้การทดสอบของคุณด้วย--trace
ซึ่งจะเปิดตัวดีบั๊กในตอนเริ่มต้นของการทดสอบทุกครั้งจากนั้นออก a j <line after assert>
เพื่อข้ามเมื่อดีบักหยุดชั่วคราวก่อนที่จะยืนยัน
คุณสามารถทำได้โดยอัตโนมัติ การใช้เทคนิคด้านบนคุณสามารถสร้างปลั๊กอินดีบักเกอร์แบบกำหนดเองได้
- ใช้
pytest_testrun_call()
hook เพื่อตรวจจับAssertionError
ข้อยกเว้น
- แยกหมายเลขบรรทัด 'offending' ของบรรทัดออกจากการย้อนกลับและอาจมีการวิเคราะห์ซอร์สโค้ดกำหนดหมายเลขบรรทัดก่อนและหลังการยืนยันที่จำเป็นในการดำเนินการกระโดดที่ประสบความสำเร็จ
- รันการทดสอบอีกครั้งแต่คราวนี้ใช้
Pdb
คลาสย่อยที่กำหนดเบรกพอยต์บนบรรทัดก่อนที่จะยืนยันและดำเนินการกระโดดโดยอัตโนมัติไปที่สองเมื่อตีเบรกพอยต์ตามด้วยการc
ดำเนินการต่อ
หรือแทนที่จะรอให้การยืนยันล้มเหลวคุณสามารถตั้งค่าเบรกพอยต์ให้โดยอัตโนมัติสำหรับแต่ละรายการที่assert
พบในการทดสอบ (อีกครั้งโดยใช้การวิเคราะห์ซอร์สโค้ดคุณสามารถแยกหมายเลขบรรทัดสำหรับast.Assert
โหนดใน AST ของการทดสอบเล็กน้อย) ดำเนินการทดสอบที่ถูกยืนยัน ใช้คำสั่งสคริปต์ดีบักเกอร์และใช้jump
คำสั่งเพื่อข้ามการยืนยันตัวเอง คุณจะต้องทำการแลกเปลี่ยน; เรียกใช้การทดสอบทั้งหมดภายใต้ดีบักเกอร์ (ซึ่งช้าเพราะล่ามจะต้องเรียกใช้ฟังก์ชันการติดตามสำหรับทุกคำสั่ง) หรือใช้สิ่งนี้กับการทดสอบที่ล้มเหลวและจ่ายราคาของการรันการทดสอบเหล่านั้นอีกครั้งตั้งแต่เริ่มต้น
ปลั๊กอินดังกล่าวจะเป็นมากในการทำงานเพื่อสร้างฉันไม่ได้จะเขียนตัวอย่างที่นี่ส่วนหนึ่งเป็นเพราะมันจะไม่พอดีกับคำตอบอยู่แล้วและส่วนหนึ่งเป็นเพราะผมไม่คิดว่ามันคุ้มค่าเวลา ฉันเพิ่งจะเปิดตัวดีบักและทำการกระโดดด้วยตนเอง การยืนยันที่ล้มเหลวเป็นการระบุข้อผิดพลาดในการทดสอบตัวเองหรือการทดสอบภายใต้รหัสดังนั้นคุณอาจเพียงแค่มุ่งเน้นไปที่การดีบักปัญหา