आप उपयोग कर रहे हैं pytest
, जो आपको असफल परीक्षणों के साथ बातचीत करने के लिए पर्याप्त विकल्प देता है। यह आपको कमांड लाइन विकल्प और यह संभव बनाने के लिए कई हुक देता है। मैं बताता हूं कि प्रत्येक का उपयोग कैसे करें और आप अपनी विशिष्ट डीबगिंग आवश्यकताओं को फिट करने के लिए कस्टमाइज़ेशन कहां कर सकते हैं।
मैं और भी अधिक विदेशी विकल्पों में जाऊँगा, जो आपको पूरी तरह से विशिष्ट कथनों को छोड़ने की अनुमति देंगे, अगर आपको वास्तव में लगता है कि आपको अवश्य करना चाहिए।
हैंडल अपवाद, मुखर नहीं
ध्यान दें कि एक असफल परीक्षण सामान्य रूप से पाइस्टेस्ट को नहीं रोकता है; यदि आपने स्पष्ट रूप से सक्षम किया है तो केवल निश्चित संख्या में विफलताओं के बाद बाहर निकलने के लिए कहें । इसके अलावा, परीक्षण विफल होते हैं क्योंकि एक अपवाद उठाया जाता है; assert
उठाता है, AssertionError
लेकिन यह एकमात्र अपवाद नहीं है जो परीक्षण को विफल कर देगा! आप नियंत्रित करना चाहते हैं कि अपवादों को कैसे नियंत्रित किया जाए, परिवर्तन नहीं assert
।
हालांकि, एक असफल अभिकथन व्यक्तिगत परीक्षा को समाप्त कर देगा । ऐसा इसलिए है क्योंकि एक बार एक try...except
ब्लॉक के बाहर एक अपवाद खड़ा हो जाने के बाद , पायथन वर्तमान फ़ंक्शन फ़्रेम को खोल देता है, और उस पर वापस नहीं जाता है।
मुझे नहीं लगता कि जैसा आप चाहते हैं, वैसा ही _assertCustom()
प्रयास फिर से चलाने के लिए आपके प्रयासों के विवरण को देखते हुए , लेकिन मैं आपके विकल्पों पर फिर भी चर्चा करूंगा।
पीडीबी के साथ पाइस्टेस्ट में पोस्टमार्टम डिबगिंग
डिबगर में विफलताओं को संभालने के विभिन्न विकल्पों के लिए, मैं --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
[ ... ]
इस स्विच के साथ, जब एक परीक्षण विफल हो जाता है तो पाइस्टेस्ट पोस्टमार्टम डिबगिंग सत्र शुरू करता है । यह अनिवार्य रूप से ठीक वही है जो आप चाहते थे; एक असफल परीक्षण के बिंदु पर कोड को रोकने के लिए और अपने परीक्षण की स्थिति पर एक नज़र डालने के लिए डिबगर खोलें। आप परीक्षण के स्थानीय चर, ग्लोबल्स और स्टैक में हर फ्रेम के स्थानीय और ग्लोबल्स के साथ बातचीत कर सकते हैं।
यहाँ पाइस्टेस्ट आपको इस बिंदु के बाद बाहर निकलने के लिए पूर्ण नियंत्रण प्रदान करता है या नहीं: यदि आप q
पद छोड़ते हैं, तो पाइस्टेस्ट रन को भी बाहर निकालता है, c
जारी रखने के लिए उपयोग करने से पाइस्टेस्ट पर नियंत्रण वापस आ जाएगा और अगला परीक्षण निष्पादित हो जाता है।
वैकल्पिक डीबगर का उपयोग करना
आप इसके लिए pdb
डीबगर के लिए बाध्य नहीं हैं ; आप --pdbcls
स्विच के साथ एक अलग डीबगर सेट कर सकते हैं । कोई भी pdb.Pdb()
संगत कार्यान्वयन कार्य करेगा, जिसमें IPython डीबगर कार्यान्वयन , या अधिकांश अन्य पायथन डीबगर ( 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
(जिस बिंदु पर पहले तो बाहर निकलता है)।
यहां एक उदाहरण कार्यान्वयन है जो प्रिंट करता है कि हम डिबग में कमी कर रहे हैं और तुरंत वापस लौटते हैं, जब तक कि परीक्षण नहीं उठाया 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 या कुछ समान का उपयोग करके अपना डिबगर नहीं लिखना चाहते। ध्यान दें कि यह एक बड़ा उपक्रम है।
फ़िल्टरिंग विफलताओं; डिबगर खोलने के लिए चुनें और चुनें
अगले स्तर तक पाइटेस्ट डिबगिंग और इंटरैक्शन हुक हैं ; ये व्यवहार के अनुकूलन के लिए हुक पॉइंट हैं, यह बदलने या बढ़ाने के लिए कि कैसे सामान्य रूप से किसी अपवाद को संभालने pdb.set_trace()
या breakpoint()
( या पायथन 3.7 या नए) के माध्यम से डिबगर में प्रवेश करने जैसी चीजें सामान्य रूप से संभालती हैं ।
इस हुक का आंतरिक कार्यान्वयन >>> entering PDB >>>
ऊपर के बैनर को भी प्रिंट करने के लिए जिम्मेदार है , इसलिए डिबगर को चलने से रोकने के लिए इस हुक का उपयोग करने का मतलब है कि आप इस आउटपुट को बिल्कुल नहीं देखेंगे। आपके पास अपना हुक हो सकता है तब मूल हुक पर प्रतिनिधि कर सकते हैं जब एक परीक्षण विफलता 'दिलचस्प' है, और इसलिए आप उपयोग कर रहे डीबगर से स्वतंत्र फ़िल्टर परीक्षण विफलताओं ! आप आंतरिक कार्यान्वयन को नाम से एक्सेस करके एक्सेस कर सकते हैं ; इसके लिए आंतरिक हुक प्लगइन का नाम दिया गया है pdbinvoke
। इसे चलाने से रोकने के लिए आपको इसे अपंजीकृत करने की आवश्यकता है लेकिन एक संदर्भ को बचाने के लिए हम इसे आवश्यकतानुसार सीधे कॉल कर सकते हैं।
इस तरह के हुक का एक नमूना कार्यान्वयन यहां दिया गया है; आप इसे किसी भी स्थान पर रख सकते हैं प्लगइन्स लोड किए गए हैं ; मैंने इसे इसमें डाला 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
एक और हुक के माध्यम से हुक के साथ प्लगइन ऑब्जेक्ट को पंजीकृत करता है 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 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। एक और अधिक पूर्ण कार्यान्वयन को प्लग-मैनेजर में सभी प्लगइन्स को लूप करना होगा ताकि प्रत्येक प्लग को स्वचालित रूप से उपयोग करके config.pluginmanager.list_name_plugin
और hasattr()
परीक्षण करने के लिए , मनमाने ढंग से प्लगइन्स को ओवरराइड किया जा सके।
असफलताएं पूरी तरह से दूर कर देती हैं
हालांकि यह आपको विफल परीक्षण डीबगिंग पर पूर्ण नियंत्रण देता है, फिर भी यह परीक्षण को विफल कर देता है, भले ही आपने किसी दिए गए परीक्षण के लिए डिबगर को खोलने का विकल्प न चुना हो। यदि आप असफलताओं को पूरी तरह से दूर करना चाहते हैं, तो आप एक अलग हुक का उपयोग कर सकते हैं pytest_runtest_call()
:।
जब पाइस्टेस्ट परीक्षण चलाता है, तो यह उपरोक्त हुक के माध्यम से परीक्षण चलाएगा, जिसके वापस लौटने None
या अपवाद बढ़ाने की उम्मीद है। इससे एक रिपोर्ट बनाई जाती है, वैकल्पिक रूप से एक लॉग प्रविष्टि बनाई जाती है, और यदि परीक्षण विफल हो जाता है, तो उपरोक्त pytest_exception_interact()
हुक कहा जाता है। तो आपको बस इतना करने की आवश्यकता है कि यह हुक क्या परिणाम देता है; एक अपवाद के बजाय इसे कुछ भी वापस नहीं करना चाहिए।
सबसे अच्छा तरीका है कि एक हुक आवरण का उपयोग करना है । हुक रैपरों को वास्तविक काम करने की ज़रूरत नहीं है, लेकिन इसके बजाय एक हुक के परिणाम के साथ क्या होता है, इसे बदलने का मौका दिया जाता है। आपको बस लाइन जोड़ना है:
outcome = yield
आपके हुक आवरण कार्यान्वयन में और आपको हुक परिणाम तक पहुँच मिलती है , जिसमें परीक्षण अपवाद भी शामिल है outcome.excinfo
। यह विशेषता परीक्षण के अपवाद को उठाए जाने पर (प्रकार, उदाहरण, ट्रेसबैक) के टपल पर सेट है। वैकल्पिक रूप से, आप outcome.get_result()
मानक try...except
हैंडलिंग को कॉल और उपयोग कर सकते हैं ।
तो आप असफल परीक्षा पास कैसे करते हैं? आपके पास 3 मूल विकल्प हैं:
- आप आवरण में कॉल करके परीक्षण को एक अपेक्षित विफलता के रूप में चिह्नित कर सकते हैं
pytest.xfail()
।
- आप आइटम को छोड़ के रूप में चिह्नित कर सकते हैं , जो बताता है कि परीक्षण को कॉल करके, पहली बार में कभी नहीं चलाया गया था
pytest.skip()
।
- आप
outcome.force_result()
विधि का उपयोग करके, अपवाद को हटा सकते हैं ; परिणाम को यहां एक खाली सूची में सेट करें (मतलब: पंजीकृत हुक कुछ भी नहीं उत्पादित 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]
) की नकल की, लेकिन आप अपने इच्छित किसी अन्य संदेश प्रारूप का उपयोग करने के लिए स्वतंत्र हैं।
सभी तीन मामलों में पाइस्टेस्ट उन परीक्षणों के लिए डिबगर नहीं खोलेगा जिनके परिणाम आपने इस पद्धति का उपयोग करके बदल दिए हैं।
अलग-अलग कथन बयान करना
यदि आप एकassert
परीक्षण के भीतर परीक्षणों को बदलना चाहते हैं , तो आप अपने आप को एक बहुत अधिक काम के लिए स्थापित कर रहे हैं। हां, यह तकनीकी रूप से संभव है, लेकिन केवल उसी कोड को फिर से लिखना जिससे कि संकलन समय पर पायथन निष्पादित करने जा रहा है ।
जब आप उपयोग करते हैं pytest
, तो यह वास्तव में पहले से ही किया जा रहा है । जब आपके मुखर विफल हो जाते हैं , तब आपको अधिक संदर्भ देने के लिए पाइएस्ट्स फिर से लिखता हैassert
; इस ब्लॉग पोस्ट को वास्तव में क्या किया जा रहा है, साथ ही _pytest/assertion/rewrite.py
स्रोत कोड के अच्छे अवलोकन के लिए देखें । ध्यान दें कि मॉड्यूल 1k लाइनों से अधिक लंबा है, और आपको यह समझने की आवश्यकता है कि पायथन के अमूर्त सिंटैक्स ट्री कैसे काम करते हैं। यदि आप ऐसा करते हैं, तो आप उस मॉड्यूल को अपने स्वयं के संशोधनों को जोड़ने के लिए एक हैंडलर के साथ आसपास के बंदरपंच कर सकते हैं ।assert
try...except AssertionError:
हालाँकि , आप केवल चयनात्मकता को अक्षम या अनदेखा नहीं कर सकते हैं, क्योंकि बाद के कथन आसानी से राज्य (विशिष्ट ऑब्जेक्ट व्यवस्था, चर सेट आदि) पर निर्भर हो सकते हैं, जो कि एक स्किप किए गए मुखर से रक्षा करने के लिए था। यदि एक मुखर परीक्षण है कि foo
नहीं है None
, तो बाद में मुखर foo.bar
अस्तित्व पर निर्भर करता है, तो आप बस AttributeError
वहाँ एक में भाग जाएगा , आदि यदि आप इस मार्ग पर जाने की जरूरत है, अपवाद को फिर से बढ़ाने के लिए छड़ी।
मैं asserts
यहाँ फिर से लिखने पर आगे विस्तार में नहीं जा रहा हूँ , क्योंकि मुझे नहीं लगता कि यह पीछा करने लायक है, इसमें शामिल काम की मात्रा नहीं दी गई है, और पोस्टमार्टम डिबगिंग के साथ आपको परीक्षण की स्थिति तक पहुंच प्रदान की गई है वैसे भी दावे की विफलता ।
ध्यान दें कि यदि आप ऐसा करना चाहते हैं, तो आपको उपयोग करने की आवश्यकता नहीं है eval()
(जो वैसे भी काम नहीं करेगा, assert
एक बयान है, इसलिए आपको exec()
इसके बजाय उपयोग करने की आवश्यकता होगी ), और न ही आपको दो बार दावा करना होगा (जो अगर अभिव्यक्ति में परिवर्तन किया गया है तो मुद्दों को जन्म दे सकता है)। आप इसके बजाय ast.Assert
एक नोड के अंदर नोड को एम्बेड करेंगे ast.Try
, और एक हैंडलर को छोड़कर एक खाली ast.Raise
नोड का उपयोग करते हैं जो अपवाद पकड़ा गया था फिर से बढ़ाएं।
डीबगर का उपयोग करके कथन को छोड़ना।
पायथन डीबगर वास्तव में / कमांड का उपयोग करके आपको स्टेटमेंट्स को छोड़ देता है । यदि आप जानते हैं सामने , जो किसी विशेष जोर होगा विफल, आप इसे बाईपास के लिए इसका उपयोग कर सकते हैं। आप अपने परीक्षणों को चला सकते हैं , जो हर परीक्षण की शुरुआत में डिबगर को खोलता है , फिर एब्सटर के ठीक पहले डीबगर को रोकने पर इसे जारी करने की अनुमति दें।j
jump
--trace
j <line after assert>
आप इसे स्वचालित भी कर सकते हैं। उपरोक्त तकनीकों का उपयोग करके आप एक कस्टम डिबगर प्लगइन बना सकते हैं
- अपवाद
pytest_testrun_call()
को पकड़ने के लिए हुक का उपयोग करता AssertionError
है
- ट्रेसबैक से लाइन 'अपेंडिंग' लाइन नंबर को निकालता है, और शायद कुछ स्रोत कोड विश्लेषण के साथ एक सफल छलांग को निष्पादित करने के लिए आवश्यक जोर से पहले और बाद में लाइन नंबर निर्धारित करता है
- परीक्षण फिर से चलाता है , लेकिन इस बार एक
Pdb
उपवर्ग का उपयोग करते हुए जो मुखर से पहले लाइन पर एक ब्रेकपॉइंट सेट करता है, और ब्रेकपाइंट हिट होने पर स्वचालित रूप से दूसरे पर एक कूद निष्पादित करता है, इसके बाद c
जारी रहता है।
या, असफल होने के लिए प्रतीक्षा करने के बजाय, आप assert
परीक्षण में पाए गए प्रत्येक के लिए ब्रेकपॉइंट्स को स्वचालित कर सकते हैं (फिर से स्रोत कोड विश्लेषण का उपयोग करके, आप ast.Assert
परीक्षण के एक एएसटी में नोड्स के लिए पंक्ति संख्याओं को निकाल सकते हैं ), परीक्षण किए गए परीक्षण को निष्पादित करें। डीबगर लिपिबद्ध कमांड का उपयोग करके, और कमांड का उपयोग करके ही मुखर jump
को छोड़ें। आपको एक व्यापार करना होगा; डिबगर के तहत सभी परीक्षण चलाएं (जो दुभाषिया के रूप में धीमा है, प्रत्येक कथन के लिए एक ट्रेस फ़ंक्शन को कॉल करना है) या केवल इसे असफल परीक्षणों पर लागू करें और खरोंच से उन परीक्षणों को फिर से चलाने की कीमत का भुगतान करें।
इस तरह के एक प्लगइन बनाने के लिए बहुत काम होगा, मैं यहां एक उदाहरण लिखने वाला नहीं हूं, आंशिक रूप से क्योंकि यह किसी भी तरह एक उत्तर में फिट नहीं होगा, और आंशिक रूप से क्योंकि मुझे नहीं लगता कि यह समय के लायक है । मैं अभी डिबगर को खोलूंगा और जंप को मैन्युअल रूप से करूंगा। एक असफल मुखर या तो परीक्षण या कोड-अंडर-टेस्ट में बग को इंगित करता है, इसलिए आप समस्या को डीबग करने पर ध्यान केंद्रित कर सकते हैं।