问题描述
我编写了一个 cronjob,它遍历帐户列表并为它们执行一些网络调用(如下所示):
I wrote a cronjob that iterates through a list of accounts and performs some web call for them (shown below):
for account in self.ActiveAccountFactory():
try:
self.logger.debug('Updating %s', account.login)
self.update_account_from_fb(account)
self.check_balances()
self.check_rois()
except Exception,e:
self.logger.exception(traceback.format_exc())
因为这项工作由 heroku 每 10 分钟运行一次,所以我不希望整个工作仅仅因为一个帐户遇到问题而失败(它发生了).我在这里放置了一个 try catch 子句,以便此任务是容错的".
Because this job is run by heroku one every 10 minutes, I do not want the entire job to fail just because one account is running into issues (it happens). I placed a try catch clause here so that this task is "fault-tolerant".
然而,我注意到当我测试时,这个 try/catch 块给我带来了神秘的问题,因为即使有一些严重的错误,任务也被允许继续执行.
However, I noticed that when I am testing, this try/catch block is giving me cryptic problems because of the task is allowed to continue executing even though there is some serious error.
在测试期间禁用 try/except 块的最佳方法是什么?
What is the best way to disable a try/except block during testing?
我想过像这样直接实现代码:
I've though about implementing the code directly like this:
for account in self.ActiveAccountFactory():
self.logger.debug('Updating %s', account.login)
self.update_account_from_fb(account)
self.check_balances()
self.check_rois()
self.logger.exception(traceback.format_exc())
在我的测试用例中,但是这使得我的测试非常笨拙,因为我正在复制大量代码.
in my test cases but then this makes my tests very clumsy as I am copying large amounts of code over.
我该怎么办?
推荐答案
首先:不要使用 except Exception
吞并所有异常.这是糟糕的设计.所以把它剪掉.
First of all: don't swallow all exceptions using except Exception
. It's bad design. So cut it out.
顺便说一句:
您可以做的一件事是为 logger.exception
方法设置一个monkeypatch.然后,您可以根据是否被调用,无论是创建模拟记录器,还是单独的测试记录器,或者是在发生某些异常时停止测试的自定义测试记录器类,来处理您认为合适的测试.您甚至可以选择通过引发错误立即结束测试.
One thing you could do is setup a monkeypatch for the logger.exception
method. Then you can handle the test however you see fit based on whether it was called, whether it's creating a mock logger, or a separate testing logger, or a custom testing logger class that stops the tests when certain exceptions occur. You could even choose to end the testing immediately by raising an error.
这是一个使用 pytest.monkeypatch
的示例一>.我喜欢 pytest
这样做的方式,因为他们已经有一个预定义的夹具设置,并且不需要样板代码.但是,还有其他方法可以做到这一点(例如使用 unittest.mock.patch
作为 unitest
模块).
Here is an example using pytest.monkeypatch
. I like pytest
's way of doing this because they already have a predefined fixture setup for it, and no boilerplate code is required. However, there are others ways to do this as well (such as using unittest.mock.patch
as part of the unitest
module).
我会给你的班级打电话SomeClass
.我们要做的是创建一个SomeClass
对象的补丁版本作为夹具.打补丁的版本不会记录到记录器;相反,它将有一个模拟记录器.记录器发生的任何事情都将记录在模拟记录器中以供稍后检查.
I will call your class SomeClass
. What we will do is create a patched version of your SomeClass
object as a fixture. The patched version will not log to the logger; instead, it will have a mock logger. Anything that happens to the logger will be recorded in the mock logger for inspection later.
import pytest
import unittest.mock as mock # import mock for Python 2
@pytest.fixture
def SomeClassObj_with_patched_logger(monkeypatch):
##### SETUP PHASE ####
# create a basic mock logger:
mock_logger = mock.Mock(spec=LoggerClass)
# patch the 'logger' attribute so that when it is called on
# 'some_class_instance' (which is bound to 'self' in the method)
# things are re-routed to mock_logger
monkeypatch.setattr('some_class_instance.logger', mock_logger)
# now create class instance you will test with the same name
# as the patched object
some_class_instance = SomeClass()
# the class object you created will now be patched
# we can now send that patched object to any test we want
# using the standard pytest fixture way of doing things
yield some_class_instance
###### TEARDOWN PHASE #######
# after all tests have been run, we can inspect what happened to
# the mock logger like so:
print('\n#### ', mock_logger.method_calls)
如果 call.exception
出现在模拟记录器的方法调用中,你就知道该方法被调用了.还有很多其他方法可以处理这个问题,这只是一种.
If call.exception
appears in the method calls of the mock logger, you know that method was called. There are a lot of other ways you could handle this as well, this is just one.
如果您使用 logging
模块,LoggerClass
应该只是 logging.Logger
.或者,您可以只执行 mock_logger = mock.Mock()
.或者,您可以创建自己的自定义测试记录器类,在调用其 exception
方法时引发异常.天空才是极限!
If you're using the logging
module, LoggerClass
should just be logging.Logger
. Alternatively, you can just do mock_logger = mock.Mock()
. Or, you could create your own custom testing logger class that raises an exception when its exception
method is called. The sky is the limit!
在任何测试中使用您的修补对象,如下所示:
Use your patched object in any test like so:
def test_something(SomeClassObj_with_patched_logger):
# no need to do the line below really, just getting
# a shorter variable name
my_obj = SomeClassObj_with_patched_logger
#### DO STUFF WITH my_obj #####
如果您不熟悉 pytest
,请参阅此培训视频 更深入的信息.
If you are not familiar with pytest
, see this training video for a little bit more in depth information.
这篇关于如何在测试期间禁用 try/except 块?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!