Creating our screen capture utility function
Selenium webdriver offers a couple methods for capturing screenshot. One works well for local instances of webdriver, and the other while much slower is better to use for RemoteWebDriver as binary data can be unpredictable across scripting over the wire.
class ScreenShotUtil:
"Screenshot Utility Class"
@staticmethod
def take_screenshot(webdriver, file_name="error.png"):
"""
@param webdriver: WebDriver.
@type webdriver: WebDriver
@param file_name: Name to label this screenshot.
@type file_name: str
"""
if isinstance(webdriver, remote.webdriver.WebDriver):
# Get Screenshot over the wire as base64
base64_data = webdriver.get_screenshot_as_base64()
screenshot_data = base64.decodestring(base64_data)
screenshot_file = open(filename, "w")
screenshot_file.write(screenshot_data)
screenshot_file.close()
else:
webdriver.save_screenshot(filename)
Adding our screenshot capture rule
In Java's JUnit, you can easily just create a MethodRule (or TestWatcher) which you can use to annotate your tests. Because Python's UnitTest does not have such a feature to register call backs or event listeners to failed test results, short of implementing or using a 3rd party Test Runner, an easy way to do this is to just create a BaseTest where we override the 'run' method and insert these calls. To do this,- Open the source code for unittest.TestCase. You can find it here, http://sourceforge.net/projects/pyunit/
- Create a BaseTest class that extends TestCase.
- Override the run() method definition with the copy from the latest version.
- Inside the exception hander for failed step, and error step, insert your call to your screen capture utility.
...
class ScreenCaptureTestCase(unittest.TestCase):
...
# Defining an init method so we can pass it a webdriver.
def __init__(self, methodName='runTest', webdriver=None, screenshot_util=None):
super(WDBaseTest, self).__init__(methodName)
if webdriver_provider == None:
self._webdriver = WebDriverSingleton.get_instance()
else:
self._webdriver = webdriver
if screenshot_util == None:
self._screenshot_util = WebScreenShotUtil
else:
self._screenshot_util = screenshot_util
...
def run(self, result=None):
"""
Overriding the run() method to insert our screenshot handler.
Most of this method is a copy of the TestCase.run() method source.
"""
orig_result = result
if result is None:
result = self.defaultTestResult()
startTestRun = getattr(result, 'startTestRun', None)
if startTestRun is not None:
startTestRun()
... more pyunit code ...
except self.failureException:
# Insert our Take Screenshot on test failure code.
fname = str(self).replace("(", "").replace(")", "").replace(" ", "_")
fmt='%y-%m-%d_%H.%M.%S_.PNG'
filename = datetime.datetime.now().strftime(fmt)
self._screenshot_util.take_screenshot(self._webdriver, filename)
result.addFailure(self, sys.exc_info())
... more pyunit code...
except:
# Do the same thing again for errors.
fname = str(self).replace("(", "").replace(")", "").replace(" ", "_")
fmt='%y-%m-%d_%H.%M.%S_.PNG'
filename = datetime.datetime.now().strftime(fmt)
self._screenshot_util.take_screenshot(self._webdriver, filename)
result.addError(self, sys.exc_info())
... more pyunit code ...
...
Now that I have inserted calls to 'take_screenshot' into the try/except blocks that handle test errors, we now will capture screenshot whenever a test extending this test fails. You can use this test case like this:
import unittest
from wtframework.wtf.testobjects.basetests import WTFBaseTest
from wtframework.wtf.web.webdriver import WTF_WEBDRIVER_MANAGER
class TestScreenCaptureOnFail(ScreenCaptureTestCase):
""""
These test cases are expected to fail. They are here to test
the screen capture on failure.
"""
# Comment out decorator to manually test the screen capture.
@unittest.expectedFailure
def test_fail(self):
driver = WTF_WEBDRIVER_MANAGER.new_driver()
driver.get('http://www.google.com')
self.fail()
#Check your /screenshots folder for a screenshot.
There you go, we have a simple method that automatically captures screenshots upon test failure.Update:
I have since then incorporated this into WTFramework,
https://github.com/wiredrive/wtframework
In WTFramework, I extended the basic TestCase class to WatchedTestCase, which allows you to register listeners.
https://github.com/wiredrive/wtframework/blob/master/wtframework/wtf/testobjects/testcase.py
This then allows me to register various listeners like my CaptureScreenShotOnErrorTestWatcher
https://github.com/wiredrive/wtframework/blob/master/wtframework/wtf/testobjects/basetests.py
3 comments:
i would like to use same method for my nose framewrok
Good article..Thanks for sharing..It was really informative.Keep update Top selenium training institutes in chennai
Selenium Testing Course
software testing course in velachery chennai
Nice and good article. It is very useful for me to learn and understand easily. Thanks for sharing your valuable information and time.
Please keep updating.
Digital Marketing Training in Chennai
Digital Marketing Course in Chennai
Post a Comment