Czy rozważałeś następujący przepływ pracy? Czytam twoje BTW
, ale twarde reguły czasami powstrzymują nas od rozwiązania naszych problemów (szczególnie jeśli jesteś w pułapce XY), więc zamierzam zaproponować ci użycie debuggera. Wpadam na testy, które zawodzą przez cały czas. Gdy śledzenie całego stosu ma kluczowe znaczenie dla rozwiązania problemu, używam kombinacji pdb
i py.test
, aby uzyskać cały shebang. Biorąc pod uwagę następujący program ...
import pytest
@pytest.mark.A
def test_add():
a = 1
b = 2
add(a,b)
def add(a, b):
assert a>b
return a+b
def main():
add(1,2)
add(2,1)
if __name__ == "__main__":
# execute only if run as a script
main()
uruchamiając komendę py.test -v -tb=short -m A code.py
wyniki w następujący wynik ...
[email protected] ~/src/python/so-answer-stacktrace: py.test -v --tb=short -m A code.py
============================= test session starts ==============================
platform darwin -- Python 2.7.5 -- pytest-2.5.0 -- /Users/art/.pyenv/versions/2.7.5/bin/python
collected 1 items
code.py:3: test_add FAILED
=================================== FAILURES ===================================
___________________________________ test_add ___________________________________
code.py:9: in test_add
> add(a,b)
code.py:12: in add
> assert a>b
E assert 1 > 2
=========================== 1 failed in 0.01 seconds ===========================
jeden prosty sposób, aby zbadać ślad stosu jest spadek punkt pdb
debugowania w test, Mark
indywidualny test ze znakiem pytest
, wywołaj ten test i sprawdź stos wewnątrz debuggera. jak tak ...
def add(a, b):
from pdb import set_trace;set_trace()
assert a>b
return a+b
Teraz, kiedy ponownie uruchomić tego samego polecenia testową dostaję zawieszony pdb
debugger. Podobnie jak ...
[email protected] ~/src/python/so-answer-stacktrace: py.test -v --tb=short -m A code.py
=========================================================================================== test session starts ============================================================================================
platform darwin -- Python 2.7.5 -- pytest-2.5.0 -- /Users/art/.pyenv/versions/2.7.5/bin/python
collected 1 items
code.py:3: test_add
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PDB set_trace (IO-capturing turned off) >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
> /Users/art/src/python/so-answer-stacktrace/code.py(13)add()
-> assert a>b
(Pdb)
Jeśli w tym momencie mam wpisać magiczne w
dla where
i uderzył enter
widzę pełną ślad stosu w całej okazałości ...
(Pdb) w
/Users/art/.pyenv/versions/2.7.5/bin/py.test(9)<module>()
-> load_entry_point('pytest==2.5.0', 'console_scripts', 'py.test')()
/Users/art/.pyenv/versions/2.7.5/lib/python2.7/site-packages/pytest-2.5.0-py2.7.egg/_pytest/config.py(19)main()
-> return config.hook.pytest_cmdline_main(config=config)
/Users/art/.pyenv/versions/2.7.5/lib/python2.7/site-packages/pytest-2.5.0-py2.7.egg/_pytest/core.py(376)__call__()
-> return self._docall(methods, kwargs)
/Users/art/.pyenv/versions/2.7.5/lib/python2.7/site-packages/pytest-2.5.0-py2.7.egg/_pytest/core.py(387)_docall()
-> res = mc.execute()
/Users/art/.pyenv/versions/2.7.5/lib/python2.7/site-packages/pytest-2.5.0-py2.7.egg/_pytest/core.py(288)execute()
-> res = method(**kwargs)
/Users/art/.pyenv/versions/2.7.5/lib/python2.7/site-packages/pytest-2.5.0-py2.7.egg/_pytest/main.py(111)pytest_cmdline_main()
-> return wrap_session(config, _main)
/Users/art/.pyenv/versions/2.7.5/lib/python2.7/site-packages/pytest-2.5.0-py2.7.egg/_pytest/main.py(81)wrap_session()
-> doit(config, session)
/Users/art/.pyenv/versions/2.7.5/lib/python2.7/site-packages/pytest-2.5.0-py2.7.egg/_pytest/main.py(117)_main()
-> config.hook.pytest_runtestloop(session=session)
/Users/art/.pyenv/versions/2.7.5/lib/python2.7/site-packages/pytest-2.5.0-py2.7.egg/_pytest/core.py(376)__call__()
-> return self._docall(methods, kwargs)
/Users/art/.pyenv/versions/2.7.5/lib/python2.7/site-packages/pytest-2.5.0-py2.7.egg/_pytest/core.py(387)_docall()
-> res = mc.execute()
/Users/art/.pyenv/versions/2.7.5/lib/python2.7/site-packages/pytest-2.5.0-py2.7.egg/_pytest/core.py(288)execute()
-> res = method(**kwargs)
/Users/art/.pyenv/versions/2.7.5/lib/python2.7/site-packages/pytest-2.5.0-py2.7.egg/_pytest/main.py(137)pytest_runtestloop()
-> item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem)
/Users/art/.pyenv/versions/2.7.5/lib/python2.7/site-packages/pytest-2.5.0-py2.7.egg/_pytest/core.py(376)__call__()
-> return self._docall(methods, kwargs)
/Users/art/.pyenv/versions/2.7.5/lib/python2.7/site-packages/pytest-2.5.0-py2.7.egg/_pytest/core.py(387)_docall()
-> res = mc.execute()
/Users/art/.pyenv/versions/2.7.5/lib/python2.7/site-packages/pytest-2.5.0-py2.7.egg/_pytest/core.py(288)execute()
-> res = method(**kwargs)
/Users/art/.pyenv/versions/2.7.5/lib/python2.7/site-packages/pytest-2.5.0-py2.7.egg/_pytest/runner.py(62)pytest_runtest_protocol()
-> runtestprotocol(item, nextitem=nextitem)
/Users/art/.pyenv/versions/2.7.5/lib/python2.7/site-packages/pytest-2.5.0-py2.7.egg/_pytest/runner.py(72)runtestprotocol()
-> reports.append(call_and_report(item, "call", log))
/Users/art/.pyenv/versions/2.7.5/lib/python2.7/site-packages/pytest-2.5.0-py2.7.egg/_pytest/runner.py(106)call_and_report()
-> call = call_runtest_hook(item, when, **kwds)
/Users/art/.pyenv/versions/2.7.5/lib/python2.7/site-packages/pytest-2.5.0-py2.7.egg/_pytest/runner.py(124)call_runtest_hook()
-> return CallInfo(lambda: ihook(item=item, **kwds), when=when)
/Users/art/.pyenv/versions/2.7.5/lib/python2.7/site-packages/pytest-2.5.0-py2.7.egg/_pytest/runner.py(137)__init__()
-> self.result = func()
/Users/art/.pyenv/versions/2.7.5/lib/python2.7/site-packages/pytest-2.5.0-py2.7.egg/_pytest/runner.py(124)<lambda>()
-> return CallInfo(lambda: ihook(item=item, **kwds), when=when)
/Users/art/.pyenv/versions/2.7.5/lib/python2.7/site-packages/pytest-2.5.0-py2.7.egg/_pytest/main.py(161)call_matching_hooks()
-> return hookmethod.pcall(plugins, **kwargs)
/Users/art/.pyenv/versions/2.7.5/lib/python2.7/site-packages/pytest-2.5.0-py2.7.egg/_pytest/core.py(380)pcall()
-> return self._docall(methods, kwargs)
/Users/art/.pyenv/versions/2.7.5/lib/python2.7/site-packages/pytest-2.5.0-py2.7.egg/_pytest/core.py(387)_docall()
-> res = mc.execute()
/Users/art/.pyenv/versions/2.7.5/lib/python2.7/site-packages/pytest-2.5.0-py2.7.egg/_pytest/core.py(288)execute()
-> res = method(**kwargs)
/Users/art/.pyenv/versions/2.7.5/lib/python2.7/site-packages/pytest-2.5.0-py2.7.egg/_pytest/runner.py(86)pytest_runtest_call()
-> item.runtest()
/Users/art/.pyenv/versions/2.7.5/lib/python2.7/site-packages/pytest-2.5.0-py2.7.egg/_pytest/python.py(1076)runtest()
-> self.ihook.pytest_pyfunc_call(pyfuncitem=self)
/Users/art/.pyenv/versions/2.7.5/lib/python2.7/site-packages/pytest-2.5.0-py2.7.egg/_pytest/main.py(161)call_matching_hooks()
-> return hookmethod.pcall(plugins, **kwargs)
/Users/art/.pyenv/versions/2.7.5/lib/python2.7/site-packages/pytest-2.5.0-py2.7.egg/_pytest/core.py(380)pcall()
-> return self._docall(methods, kwargs)
/Users/art/.pyenv/versions/2.7.5/lib/python2.7/site-packages/pytest-2.5.0-py2.7.egg/_pytest/core.py(387)_docall()
-> res = mc.execute()
/Users/art/.pyenv/versions/2.7.5/lib/python2.7/site-packages/pytest-2.5.0-py2.7.egg/_pytest/core.py(288)execute()
-> res = method(**kwargs)
/Users/art/.pyenv/versions/2.7.5/lib/python2.7/site-packages/pytest-2.5.0-py2.7.egg/_pytest/python.py(188)pytest_pyfunc_call()
-> testfunction(**testargs)
/Users/art/src/python/so-answer-stacktrace/code.py(9)test_add()
-> add(a,b)
> /Users/art/src/python/so-answer-stacktrace/code.py(13)add()
-> assert a>b
(Pdb)
zrobić wiele pracy w frameworkach. pdb
+ where
daje wszystko, aż do faktycznego punktu wejścia programu. Widać tam pochowane moje funkcje, a także ramy biegacza testowego. Gdyby to było Django lub Flask, zobaczyłbym wszystkie ramki stosów związane z wewnętrznymi strukturami.Jest to moja przerwa dla wszystkich, gdy wszystko idzie naprawdę źle.
Jeśli masz test z dużą ilością powtórzeń lub warunków, możesz odwieszać się od nowa na tych samych liniach. Rozwiązaniem jest sprytne podejście do wyboru instrumentu przy pomocy pdb
. Zagnieżdżanie go w warunkowej lub instrumentacyjnej iteracji/rekurencji z warunkiem (zasadniczo mówiąc: Kiedy to staje się True
, następnie zawiesić, aby sprawdzić, co się dzieje). Ponadto, pdb
pozwala spojrzeć na cały kontekst środowiska wykonawczego (przypisania, stan itp.).
Dla twojego przypadku wygląda na to, że porządkowa oprzyrządowanie check_perm
jest w porządku.
Tak, podoba mi się wyjście cgitb (i strona debugowania django). Sądzę, że nie dają mi informacji, których szukam. W moim przypadku nie dostaję wyjątku. Metoda zwraca wartość. Ale skąd wzięła się faktyczna wartość? Zaktualizowałem pytanie, aby zilustrować to, czego chcę. Niemniej jednak dziękuję za twoją opinię. – guettli