I want to automatic capturing screenshots if my webdriver tests failed (any exception or assertion error). I am using Python unittest and Selenium Webdriver. Does anyone have any solution to this problem?
8 Answers
do some webdriver stuff in Firefox... save screenshot on any exception to a dated image file:
from datetime import datetime
from selenium import webdriver
browser = webdriver.Firefox()
try:
# do some webdriver stuff here
except Exception as e:
print e
now = datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
browser.get_screenshot_as_file('screenshot-%s.png' % now)

- 59,062
- 28
- 129
- 143
-
Thanks! I thought that it was a right way using try:except and now I saw this – d1minshakov Aug 21 '12 at 16:04
-
1This works well, but swallowing the exception this way stops the unit test harness from reporting an error. If using this code in a unittest class containing multiple tests, it's worth adding 'raise e' to the end of the except block. – Journeyman Apr 25 '19 at 08:37
Another method would be to add the following to your tearDown
method:
if sys.exc_info()[0]:
test_method_name = self._testMethodName
self.driver.save_screenshot("Screenshots/%s.png" % test_method_name)
This would be assuming a test class like this:
class SeleniumTest(unittest2.TestCase):
...
def tearDown(self):
if sys.exc_info()[0]:
test_method_name = self._testMethodName
self.driver.save_screenshot("Screenshots/%s.png" % test_method_name)
super(SeleniumTest, self).tearDown()
def test_1(self):
...
def test_2(self):
...

- 5,524
- 3
- 37
- 62

- 313
- 2
- 16
For Future reference/People here is a solution that works in Python3, that works both for an Exception and on a failed Assert.
(Based on https://stackoverflow.com/a/23176373/9427691)
#!/usr/bin/env python
"""
An Example code to show the set-up with screen-shot on exception.
"""
import unittest
from selenium import webdriver
class TestDemo(unittest.TestCase):
"""An Example test Case, to show off the set-up of a screen-shot on exception."""
def setUp(self):
"""Set up the Firefox Browser and the Tear Down."""
self.driver = webdriver.Firefox()
self.driver.delete_all_cookies()
# NOTE: In addCleanup, the first in, is executed last.
self.addCleanup(self.driver.quit)
self.addCleanup(self.screen_shot)
self.driver.implicitly_wait(5)
def screen_shot(self):
"""Take a Screen-shot of the drive homepage, when it Failed."""
for method, error in self._outcome.errors:
if error:
self.driver.get_screenshot_as_file("screenshot" + self.id() + ".png")
def test_demo(self):
"""A test case that fails because of missing element."""
self.driver.get("http://www.google.com")
self.driver.find_element_by_css_selector("div.that-does-not-exist")
def test_demo2(self):
"""A test case that fails because assert."""
self.driver.get("https://stackoverflow.com")
self.assertEqual(True, False)
if __name__ == '__main__':
unittest.main(verbosity=2)
The
self._outcome.errors
are Python3 only, so for Python2 use
self._outcomeForDoCleanups.errors
instead.
For the ones that only want a Screen-shot on exceptions. You should take a look at this link: http://blog.likewise.org/2015/01/automatically-capture-browser-screenshots-after-failed-python-ghostdriver-tests/

- 181
- 2
- 4
-
2Instead of adding the screen_shot method through addCleanup(), it is also possible to place the logic in tearDown() – Sundae Jan 30 '20 at 10:44
Here is a solution using a decorator that wrapps every method on a class that starts test_
with a wrapper that takes a screenshot if the method raises and Exception. The browser_attr
is used to tell the decorator how to obtain the web browser (driver).
from functools import partialmethod
def sreenshotOnFail(browser_attr='browser'):
def decorator(cls):
def with_screen_shot(self, fn, *args, **kwargs):
"""Take a Screen-shot of the drive page, when a function fails."""
try:
return fn(self, *args, **kwargs)
except Exception:
# This will only be reached if the test fails
browser = getattr(self, browser_attr)
filename = 'screenshot-%s.png' % fn.__name__
browser.get_screenshot_as_file(filename)
print('Screenshot saved as %s' % filename)
raise
for attr, fn in cls.__dict__.items():
if attr[:5] == 'test_' and callable(fn):
setattr(cls, attr, partialmethod(with_screen_shot, fn))
return cls
return decorator
@sreenshotOnFail()
class TestDemo(unittest.TestCase):
def setUp(self):
"""Set up the Firefox Browser and the Tear Down."""
self.browser = webdriver.Firefox()
def test_demo2(self):
"""A test case that fails because assert."""
self.driver.get("https://stackoverflow.com")
self.assertEqual(True, False)

- 633
- 7
- 6
You can start form exploring self._outcome.errors[1]
where it is possible to find information about the errors.
i.e. below code will work only for assertion errors
def tearDown(self):
if self._outcome.errors[1][1] and hasattr(self._outcome.errors[1][1][1], 'actual'):
self.driver.save_screenshot(self._testMethodName + '.png')

- 22,778
- 19
- 100
- 117
try:
page2.fill_up_company_info()
except Exception as e:
with pytest.raises(WebDriverException):
pytest.fail( f"{e} for error message",
allure.attach(self.driver.get_screenshot_as_png(),name="screenshot",attachment_type=AttachmentType.PNG))

- 1,009
- 3
- 13
- 27

- 81
- 1
- 2
For Django 2.2.2 (which uses unittest) in my class for selenium tests, which inherited from StaticLiveServerTestCase I've overrided _feedErrorsToResult method. Also this approach provides tricky way to know name of called method for convinient screenshot investigation.
@classmethod
def _feedErrorsToResult(cls, result, errors):
"""
Overriding private method at %library root%/Lib/unittest/case.py
so you can take screenshot with any failed test and find name of the method
"""
if SELENIUM_TAKE_SCREENSHOTS:
for test, exc_info in errors:
if exc_info is not None:
now = datetime.now().strftime('%y-%m-%d_%H-%M-%S')
test_name = exc_info[2].tb_frame.f_locals["test_case"]._testMethodName
# noinspection PyUnresolvedReferences
cls.selenium.get_screenshot_as_file('%s/%s-%s-%s.png' % (SELENIUM_SCREENSHOTS_PATH, cls.__name__, test_name, now))
# noinspection PyUnresolvedReferences
super()._feedErrorsToResult(cls, result, errors)

- 470
- 6
- 9
For me help this solution:
def teardown_method(self, method):
"""Driver elimination"""
if sys.exc_info():
allure.attach('screenshot', self.driver.get_screenshot_as_png(), type=AttachmentType.PNG)
self.driver.quit()
pass

- 1
- 1