PyDev 单元测试:如何捕获记录到“捕获的输出”中的logging.Logger 的文本
我正在使用 PyDev 来开发和单元测试我的 Python 应用程序。 至于单元测试,除了没有内容记录到日志框架之外,一切都运行良好。 PyDev 的“捕获输出”未捕获记录器。
我已经将记录的所有内容转发到标准输出,如下所示:
import sys
logger = logging.getLogger()
logger.level = logging.DEBUG
logger.addHandler(logging.StreamHandler(sys.stdout))
尽管如此,“捕获的输出”不会显示记录到记录器的内容。
这是一个示例单元测试脚本:test.py
import sys
import unittest
import logging
logger = logging.getLogger()
logger.level = logging.DEBUG
logger.addHandler(logging.StreamHandler(sys.stdout))
class TestCase(unittest.TestCase):
def testSimpleMsg(self):
print("AA")
logging.getLogger().info("BB")
控制台输出是:
Finding files... done.
Importing test modules ... done.
testSimpleMsg (itf.lowlevel.tests.hl7.TestCase) ... AA
2011-09-19 16:48:00,755 - root - INFO - BB
BB
ok
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
但是测试的捕获输出是:
======================== CAPTURED OUTPUT =========================
AA
有人知道如何捕获在执行此测试期间记录到logging.Logger
的所有内容吗?
I am using PyDev for development and unit-testing of my Python application.
As for unit-testing, everything works great except the fact that no content is logged to the logging framework. The logger is not captured by the "Captured output" of PyDev.
I'm already forwarding everything logged to the standard output like this:
import sys
logger = logging.getLogger()
logger.level = logging.DEBUG
logger.addHandler(logging.StreamHandler(sys.stdout))
Nevertheless the "Captured output" does not display the stuff logged to loggers.
Here's an example unittest-script: test.py
import sys
import unittest
import logging
logger = logging.getLogger()
logger.level = logging.DEBUG
logger.addHandler(logging.StreamHandler(sys.stdout))
class TestCase(unittest.TestCase):
def testSimpleMsg(self):
print("AA")
logging.getLogger().info("BB")
The console output is:
Finding files... done.
Importing test modules ... done.
testSimpleMsg (itf.lowlevel.tests.hl7.TestCase) ... AA
2011-09-19 16:48:00,755 - root - INFO - BB
BB
ok
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
But the CAPTURED OUTPUT for the test is:
======================== CAPTURED OUTPUT =========================
AA
Does anybody know how to capture everything that is logged to a logging.Logger
during the execution of this test?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
问题是
unittest
运行程序在测试开始之前替换了sys.stdout
/sys.stderr
,并且StreamHandler
> 仍在写入原始sys.stdout
。如果将“当前”
sys.stdout
分配给处理程序,它应该可以工作(请参阅下面的代码)。不过,更好的方法是在测试期间添加/删除处理程序:
The issue is that the
unittest
runner replacessys.stdout
/sys.stderr
before the testing starts, and theStreamHandler
is still writing to the originalsys.stdout
.If you assign the 'current'
sys.stdout
to the handler, it should work (see the code below).Although, a better approach would be adding/removing the handler during the test:
我厌倦了必须手动将 Fabio 的出色代码 添加到所有
setUp
中,因此我将其子类化unittest.TestCase
和一些__metaclass__
ing:现在您的测试用例可以简单地继承
LoggedTestCase
,即class TestCase(LoggedTestCase)
而不是class TestCase(unittest.TestCase)
就完成了。或者,您可以添加__metaclass__
行并在测试或稍微修改的LogThisTestCase
中定义logger
。I grew tired of having to manually add Fabio's great code to all
setUp
s, so I subclassedunittest.TestCase
with some__metaclass__
ing:Now your test case can simply inherit from
LoggedTestCase
, i.e.class TestCase(LoggedTestCase)
instead ofclass TestCase(unittest.TestCase)
and you're done. Alternatively, you can add the__metaclass__
line and define thelogger
either in the test or a slightly modifiedLogThisTestCase
.有些人可能会访问此线程以找到将测试期间创建的日志转发到控制台或 PyDev 的方法。上面的答案已经提供了一些解决方案。
如果想在实际测试中捕获特定日志,我发现从 Python 3.4 开始,
unittest.TestCase
提供了assertLogs()
,它返回一个捕获当前日志的上下文管理器消息。从 unittest 文档:消息在 <代码>cm.output。有关更详细的信息(如时间、文件、行号等),
cm.records
包含LogRecords
。所有这些并没有直接解决 PyDev 面临的 OP,而是提供了一种以编程方式检查创建的消息的方法
。那些熟悉pytest,可以使用
--log-cli-level=LEVEL
标志,(例如py测试--log-cli-level=info)。Some people probably visit this thread to find a way to forward the logs created during testing to the console or to PyDev. The above answers already provide some solutions.
If one wants to capture particular logs within an actual test, I found that since Python 3.4,
unittest.TestCase
offersassertLogs()
, which returns a context manager that captures current log messages. From the unittest docs:The messages are captured in
cm.output
. For more detailed information (like timing, file, line-number etc.,cm.records
contains a list ofLogRecords
.All this does not directly address the OP faced with PyDev, but offers a way to examine the created messages programmatically.
For those familiar with pytest, one can forward nicely formatted log messages to the console using the
--log-cli-level=LEVEL
flag, (for instancepytest --log-cli-level=info
).我建议使用 LogCapture 并测试您是否确实记录了您期望记录的内容:
http://testfixtures.readthedocs.org/en/latest/logging.html
I'd suggest using a LogCapture and testing that you really are logging what you expect to be logging:
http://testfixtures.readthedocs.org/en/latest/logging.html
阅读此答案和其他一些相关线程(谢谢!)后,这是我放在一起的上下文管理器,它将捕获记录器的输出(如果发送了任何输出)。
使用示例:
由于OP要求将其放入捕获的stdout流中,因此您可以在
__exit__
中将其打印到stdout,因此添加一行,如下所示:此解决方案的不同之处在于它将收集记录输出并在所有正常的 print() 调用(如果有)之后一次性将其转储出来。所以这可能是也可能不是OP所追求的,但这很适合我的需求。
After reading the answers in this and a few other related threads (thank you!), here is the context manager I put together, that will capture the logger's output (if any was sent).
Usage example:
As the OP asked for getting it into the captured stdout stream, you can print it to stdout in
__exit__
, so adding one extra line as follows:This solution is different in that it will gather the logging output and dump it out at the end all at once, after all the normal
print()
calls if any. So it may or may not be what OP is after, but this worked well for my needs.我也遇到了这个问题。我最终对 StreamHandler 进行子类化,并使用获取 sys.stdout 的属性覆盖流属性。这样,处理程序将使用 unittest.TestCase 已交换到 sys.stdout 的流:
然后您可以在运行测试之前设置日志记录处理程序,如下所示(这会将自定义处理程序添加到根记录器):
如果,像我一样,您将测试放在单独的模块中,您可以在每个单元测试模块的导入之后放置一行,以确保在运行测试之前设置日志记录:
这可能不是最干净的方法,但它非常简单且有效对我来说很好。
I came across this problem also. I ended up subclassing StreamHandler, and overriding the stream attribute with a property that gets sys.stdout. That way, the handler will use the stream that the unittest.TestCase has swapped into sys.stdout:
You can then setup the logging handler before running tests like so (this will add the custom handler to the root logger):
If, like me, you have your tests in separate modules, you can just put a line after the imports of each unit test module that will make sure the logging is setup before tests are run:
This might not be the cleanest approach, but it's pretty simple and worked well for me.
我创建了这个单元测试:
I created this unit test:
如果您有不同的初始化器模块用于测试、开发和生产,那么您可以在初始化器中禁用任何内容或重定向它。
我有 local.py、test.py 和 production.py,它们都继承自 common.y
common.py 执行所有主要配置,包括此代码片段:
然后在 test.py 中我有这个:
这用 FileHandler 替换了控制台处理程序,并且意味着仍然可以进行日志记录,但我不必接触生产代码库。
If you have different initaliser modules for test, dev and production then you can disable anything or redirect it in the initialiser.
I have local.py, test.py and production.py that all inherit from common.y
common.py does all the main config including this snippet :
Then in test.py I have this:
This replaces the console handler with a FileHandler and means still get logging but I do not have to touch the production code base.
这是一个小技巧,但对我有用。当您想要显示捕获的日志时,请添加此代码。不需要后将其删除。
示例:
更新:
顺便说一下,这不是一个长期解决方案,当您想要快速调试目标函数上的某些内容时,此解决方案很有帮助。
一旦断言失败,
unittest
将抛出哪些函数出现错误,并捕获并显示print
、logging.*
内容。This is a small hack but it works for me. Add this code when you want to display captured logs. Remove it after no needed.
Example:
Updated:
By the way, this is not a long term solution, this solution is helpful when you want to quick debug something on target functions.
Once assert is fail,
unittest
will throw which functions are getting errors and also capture and displayprint
,logging.*
content.