Python 如何在测试期间禁用try/except块?

Python 如何在测试期间禁用try/except块?,python,testing,Python,Testing,我编写了一个cronjob,它遍历帐户列表并为它们执行一些web调用(如下所示): 因为这个作业是由heroku one每10分钟运行一次,所以我不希望整个作业因为一个帐户出现问题而失败(这种情况经常发生)。我在这里放了一个try-catch子句,以便该任务是“容错的” 但是,我注意到,当我进行测试时,这个try/catch块给我带来了一些隐秘的问题,因为即使出现了一些严重错误,任务仍然可以继续执行 在测试期间禁用try/except块的最佳方法是什么 我已经考虑过如何像这样直接实现代码: fo

我编写了一个cronjob,它遍历帐户列表并为它们执行一些web调用(如下所示):

因为这个作业是由heroku one每10分钟运行一次,所以我不希望整个作业因为一个帐户出现问题而失败(这种情况经常发生)。我在这里放了一个try-catch子句,以便该任务是“容错的”

但是,我注意到,当我进行测试时,这个try/catch块给我带来了一些隐秘的问题,因为即使出现了一些严重错误,任务仍然可以继续执行

在测试期间禁用try/except块的最佳方法是什么

我已经考虑过如何像这样直接实现代码:

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())
在我的测试用例中,这使得我的测试非常笨拙,因为我正在复制大量代码


我该怎么办

try…除了
块在测试时比较困难,因为它们捕获并试图处理您真正希望看到的错误。你已经发现了。在测试过程中

except Exception as e:
(不要使用
异常,e
,它不向前兼容)替换在您的环境中不太可能发生的异常类型,例如

except AssertionError as e:

文本编辑器将为您执行此操作(然后将其反转),只需单击几下鼠标。

您可以通过添加
\u testing=False
参数使callables test感知。在测试时,使用该代码在callable for中编写备用路径。然后从测试文件调用时,pass _testing=True

对于这个问题中出现的情况,将
if\u testing:raise
放在异常主体中会“uncatch”异常

调节模块级别代码是骗子。为了在包
pack
中测试模块
mod
时获得特殊行为,我将

_testing = False  # in `pack.__init__`

from pack import _testing  # in pack.mod
然后
test\u mod

import pack
pack._testing = True
from pack import mod

首先:不要使用
Exception
吞咽所有异常。这是个糟糕的设计。所以别说了

这样一来:

您可以做的一件事是为
logger.exception
方法设置monkeypatch。然后,您可以根据是否调用该测试、它是创建模拟记录器、单独的测试记录器,还是在发生某些异常时停止测试的自定义测试记录器类,以您认为合适的方式处理该测试。您甚至可以选择通过引发错误立即结束测试

下面是一个使用的示例。我喜欢
pytest
这样做,因为他们已经有了一个预定义的fixture设置,不需要样板代码。但是,也有其他方法可以做到这一点(例如,将其用作的一部分)

我会给你的班级打电话
SomeClass
。我们将要做的是创建一个补丁版本的
SomeClass
对象作为固定装置。补丁版本将不会登录到记录器;相反,它将有一个模拟记录器。记录器发生的任何情况都将记录在模拟记录器中,以便稍后检查

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
,则您知道该方法已被调用。你也可以用很多其他的方法来处理这个问题,这只是其中之一

如果您使用的是
logging
模块,
LoggerClass
应该是
logging.Logger
。或者,您可以只执行
mock\u logger=mock.mock()
。或者,您可以创建自己的自定义测试记录器类,该类在调用其
exception
方法时引发异常。天空是极限

在任何测试中使用修补对象,如:

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
,请参阅以获取更深入的信息

除例外情况外,不要使用毯子
。将适当的异常处理放在代码中正确的位置。在
except
块中添加一个简单的
raise
,以重新引发原始异常。
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 #####