以某种方式使用py.test时可以使用python调试器进行调试吗?


71

我正在使用py.test对python程序进行单元测试。我希望使用python调试器以正常方式调试测试代码(在代码中我的意思是pdb.set_trace()),但是我无法使其正常工作。

将pdb.set_trace()放入代码中不起作用(引发IOError:捕获输出时从stdin读取)。我也尝试使用--pdb选项运行py.test,但是如果我想探索断言之前发生的事情,那似乎并没有解决问题。当断言失败时,它会中断,并且从那一行继续进行就意味着终止程序。

有谁知道获取调试的方法,或者调试和py.test并不意味着在一起吗?

Answers:


109

这非常简单:assert 0在代码中放置一个要开始调试的位置,然后使用以下命令运行测试:

py.test --pdb 

完成:)

另外,如果您使用的是pytest-2.0.1或更高版本,则还可以使用pytest.set_trace()帮助程序,可以将其放在测试代码中的任何位置。这是文档。在将您发送到pdb调试器命令行之前,请务必在内部禁用捕获功能。


如果您只想调试断言之前发生的事情,那就很好了。如果有py.test.set_trace()(也可以重新启用stdin并调用pdb.set_trace()(或类似方法),那也很好。断言0的问题是不可能(AFAIK)抑制异常并继续使用调试器,最好使用一种调用调试器而不改变逻辑流程的方法
Jason R. Coombs,2010年

嗨,杰森。我明白并同意。应该有一个“ py.test.pdb()”或类似的东西,无论是否带有“ -s”,它都可以正常工作。如果您提出问题,我将继续执行。
hpk42 2010年

4
嗨,杰森。我刚刚添加了py.test.set_trace(),请参见bitbucket.org/hpk42/py-trunk/changeset/1d7b0838917f,您可能可以使用“ pip install URL”安装开发版本,其中URL是zip文件。此处:hudson.testrun.org/view/pytest/job/py-trunk-sdist(对不起,似乎StackOverflow严重截断了URL,因此无法粘贴完整的URL)
hpk42 2010年

1
您可以安装@Sardathrion,pdbpp以获得更好的体验。
Peque

@Peque从那时起,我就搬到了这里,pdbpp因为体验确实更好。☺
Sardathrion -对SE滥用

41

我发现可以在禁用捕获的情况下运行py.test,然后照常使用pdb.set_trace()。

> py.test --capture=no
============================= test session starts ==============================
platform linux2 -- Python 2.5.2 -- pytest-1.3.3
test path 1: project/lib/test/test_facet.py

project/lib/test/test_facet.py ...> /home/jaraco/projects/project/lib/functions.py(158)do_something()
-> code_about_to_run('')
(Pdb)

4
这正是我设置pdb的方式(而不是--pdb)。注意:您可以使用“ -s”代替“ --capture = no”
alfredodeza,2011年

1
多年以来,不再需要禁用捕获。只需将您的pdb.set_trace()语句添加到运行堆栈中的某个位置即可。
杰森·库姆斯

1
@ JasonR.Coombs但是ipdb.set_trace()不起作用,或者breakpoint()可能指向它。使用-s仍然有效。
user2561747 '19

这似乎不再起作用。pdb.set_trace()在测试代​​码中的某个地方添加一个常规代码,然后像往常一样运行pytest-s--capture=no仅运行pytest,打印测试摘要,并且永远不会进入调试器。
伊利

@ JasonR.Coombs我的经验是,如果我不及格-s,则pytest会因OSError: pytest: reading from stdin while output is captured! Consider using -s而失败.
Gerrit


2

我对py.test不太熟悉,对于unittest来说,您可以执行以下操作。也许py.test是类似的:

在您的测试模块(mytestmodule.py)中:

if __name__ == "__main__":
    unittest.main(module="mytestmodule")

然后使用

python -m pdb mytestmodule.py

您将获得一个交互式pdb shell。

查看文档,看起来py.test有一个--pdb命令行选项:

http://codespeak.net/py/dist/test/features.html


彼得,谢谢你的建议。python -m pdb替代方案将引导我完成脚本,但不调用函数,因此尽管对我的Python开发很有用,但我看不到如何使这一功能起作用。我提到了--pdb选项,但是除非有人能想到如何使用它,否则我也不会继续使用它。
乔尔2010年

我建议阅读pdb手册并学习击键。pdb将打印接下来要执行的功能。如果键入“ s”,则将进入该功能。如果键入“ n”,这是默认值,则只需转到下一行代码。当您想进入“主”例程时,很有可能是按“ n”而不是“ s”。
彼得·里昂斯

2
py.test不是这样工作的。py.test的小型但有效测试代码:def test_arithmetic:断言2 + 2 == 4这足以进行单元测试。没有“主”例程,只有以“ test_”开头的函数。如果使用普通的python运行它,它将仅定义test_arithmetic,而不运行它。但py.test的发现功能开始TEST_并运行他们对我来说,考虑的失败照顾断言等
乔尔

1

与Peter Lyon的答案类似,但是有了pytest所需的确切代码,您可以将以下内容添加到pytest模块的底部(my_test_module.py):

if __name__ == "__main__":
    pytest.main(["my_test_module.py", "-s"])

然后,您可以从命令行调用调试器:

pdb3 my_test_module.py

繁荣。您正在调试器中,并且能够输入调试器命令。此方法不会让您的测试代码被set_trace()调用搞乱,并且将在pytest中“正常”运行。


0

添加和删除断点而无需编辑源文件

尽管可以通过在代码中添加breakpoint()set_trace()语句来添加断点,但是这种方法存在两个问题:

  • 首先,一旦开始运行代码,就无法删除断点。我经常发现,一旦我开始运行代码并到达初始断点,便想放置另一个代码并删除初始断点。后breakpoint()滴我到调试器中我可以添加额外的断点,但我不能删除初始之一。尽管可以通过提高初始breakpoint语句来缓解这种情况,但是,如果您具有参数化测试,那么即使这样做也很有限。我可能会发现自己cont经常重复。
  • 其次,它需要更改源代码。您需要记住breakpoint()在将任何代码提交到版本控制之前删除所有命令,必须在切换分支之前删除它们,等等。有时我发现我想使用调试器来比较两个分支之间的测试运行,并且必须编辑源代码每次添加一个断点的代码会使这项工作变得相当慢,而且容易出错。我什至可能要在我正在调用的库中添加一个断点,在这种情况下,我正在编辑的文件甚至可能不在我的git存储库中,而是在我的conda环境中的某个深处,这增加了忘记删除它的风险。在我看来,编辑文件以添加断点是很丑陋的。

要以交互方式添加和删除断点而不编辑任何源文件,您可以pytest在bash shell中进行如下操作:

python -mipdb $(type -p pytest) -s test_fileset.py

-s标志在这里至关重要,因为它阻止pytest与stdin和stdout发生混乱,并且在调试器中运行时,pytest将无法与stdin和stdout陷入混乱,并且一切都会出错。对于不同的外壳,确切的调用语法将有所不同。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.