[英]How to execute code only on test failures with python unittest2?
I have some class-based unit tests running in python's unittest2 framework. 我在python的unittest2框架中运行了一些基于类的单元测试。 We're using Selenium WebDriver, which has a convenient
save_screenshot()
method. 我们正在使用Selenium WebDriver,它具有方便的
save_screenshot()
方法。 I'd like to grab a screenshot in tearDown() for every test failure, to reduce the time spent debugging why a test failed. 我想在每个测试失败时在tearDown()中抓取一个屏幕截图,以减少调试为什么测试失败的时间。
However, I can't find any way to run code on test failures only. 但是,我找不到仅在测试失败时运行代码的任何方法。
tearDown()
is called regardless of whether the test succeeds, and I don't want to clutter our filesystem with hundreds of browser screenshots for tests that succeeded. 无论测试是否成功,都将调用
tearDown()
,并且我不希望使用成百上千的浏览器屏幕快照来使我们的文件系统混乱,以确保测试成功。
How would you approach this? 您将如何处理?
Found a solution - I can override failureException
: 找到了解决方案-我可以覆盖
failureException
:
@property
def failureException(self):
class MyFailureException(AssertionError):
def __init__(self_, *args, **kwargs):
self.b.save_screenshot('%s.png' % self.id())
return super(MyFailureException, self_).__init__(*args, **kwargs)
MyFailureException.__name__ = AssertionError.__name__
return MyFailureException
This seems incredibly hacky but it seems to work so far. 这似乎难以置信,但到目前为止它似乎仍然有效。
覆盖fail()
以生成屏幕截图,然后调用TestCase.fail(self)
吗?
sys.exc_info()
should give you exit information on whether a test failed or not. sys.exc_info()
应该为您提供有关测试是否失败的退出信息。 So something like this: 所以像这样:
def tearDown(self):
if sys.exc_info()[0]:
path = os.path.join(os.path.dirname(os.path.abspath(__file__)), '../failures', self.driver.browser)
if not os.path.exists(path):
try:
os.makedirs(path)
except Exception:
# Since this might not be thread safe
pass
filename = '%s.%s.png' % (self.__class__.__name__, self._testMethodName)
file_path = os.path.join(path, filename)
self.driver.get_screenshot_as_file(file_path)
Here is similar approach to @craigds answer , but with directory support and better compatibility with Python 3: 这是与@craigds答案类似的方法,但具有目录支持和与Python 3的更好兼容性:
@property
def failureException(self):
class MyFailureException(AssertionError):
def __init__(self_, *args, **kwargs):
screenshot_dir = 'reports/screenshots'
if not os.path.exists(screenshot_dir):
os.makedirs(screenshot_dir)
self.driver.save_screenshot('{0}/{1}.png'.format(screenshot_dir, self.id()))
return super(MyFailureException, self_).__init__(*args, **kwargs)
MyFailureException.__name__ = AssertionError.__name__
return MyFailureException
This was actually found in this blog . 实际上是在此博客中找到的。
I've extended it further more with argparse
: 我用
argparse
进一步扩展了它:
parser.add_argument("-r", "--reports-dir", action="store", dest="dir", help="Directory to save screenshots.", default="reports")
so the dir can be specified dynamically either by system variable or passed argument: 因此,可以通过系统变量或传递的参数动态指定目录:
screenshot_dir = os.environ.get('REPORTS_DIR', self.args.dir) + '/screenshots'
This is especially useful, if you've additional wrapper to run all your scripts, like a base class. 如果您有其他包装程序来运行所有脚本(如基类),则此功能特别有用。
Use a decorator around each test. 在每个测试周围使用装饰器。
The safest way to remember to decorate new tests, or to avoid going back and decorating a bunch of existing tests, is to use a metaclass to wrap all of the test functions. 记住装饰新测试或避免返回并装饰一堆现有测试的最安全方法是使用元类包装所有测试功能。 The How to wrap every method of a class?
如何包装一个类的每个方法? answer provides the basics of what you need.
答案提供了您所需的基础知识。
You probably should filter the functions that are wrapped down to just the tests, eg: 您可能应该过滤仅包含测试的功能,例如:
class ScreenshotMetaClass(type):
"""Wraps all tests with screenshot_on_error"""
def __new__(meta, classname, bases, classDict):
newClassDict = {}
for attributeName, attribute in classDict.items():
if type(attribute) == FunctionType and 'test' in attributeName.lower():
# replace the function with a wrapped version
attribute = screenshot_on_error(attribute)
newClassDict[attributeName] = attribute
return type.__new__(meta, classname, bases, newClassDict)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.