2017-01-19 3 views
0

Я хотел бы настроить хороший способ захвата снимков экрана, когда некоторые из наших пробных тестов Robot Framework не пройдут. Конечно, я могу добавить:Захват скриншота при сбое теста в сложном тестовом комплекте

Run Keyword If Test Failed Capture Page Screenshot 

Чтобы проверить Teardown, но учитывая, что я есть огромные и сложные наборы тестов с сотнями тестов и вложенной структуры - мне нужно, чтобы добавить это так много разборок, что кажется некрасиво меня.

Я немного экспериментировал. Я думал, что путь вперед должен был использовать listener. Поэтому я пробовал это:

class ExtendedSelenium(Selenium2Library): 
    ROBOT_LISTENER_API_VERSION = 3 

    def __init__(self, timeout=5.0, implicit_wait=0.0, run_on_failure='Capture Page Screenshot', screenshot_root_directory=None): 
     super(ExtendedSelenium, self).__init__(timeout, implicit_wait, run_on_failure, screenshot_root_directory) 
     self.ROBOT_LIBRARY_LISTENER = self 

    def _end_test(self, data, result): 
     if not result.passed: 
      screenshot_name = data.id + data.name.replace(" ", "_") + ".png" 
      try: 
       self.capture_page_screenshot(screenshot_name) 
      except: 
       pass 

Он фиксирует скриншот, но изображение не отображается в журнале. Я в состоянии отобразить его в тестовом сообщении, добавив этот шаг после захвата:

BuiltIn().set_test_message("*HTML* {} <br/> <img src={}>".format(result.message, screenshot_name)) 

Но все-таки, это не самое лучшее.

Тогда я попробовал другой подход с интерфейсом Visitor (используется с --prerunmodifier):

from robot.api import SuiteVisitor 


class CaptureScreenshot(SuiteVisitor): 

    def end_test(self, test): 
     if test.status == 'FAIL': 
      test.keywords.create('Capture Page Screenshot', type='teardown') 

Но он заменяет любой существующий тест Teardown на новую (только одно ключевое слово «Capture страницу Снимок экрана»). Я думал, что смогу изменить существующий Teardowns, добавив ключевое слово Capture, но я не был.

Есть ли какой-нибудь хороший, чистый, питонический способ сделать это? Я что-то пропустил?

+2

Я думаю, что путинский способ заключается в том, чтобы добавить надлежащее тестовое отключение к каждому тесту. Похоже, вы не ищете питоновское решение, а скорее обходное решение. Знаете ли вы, что вы можете определить тестовое разрывы на уровне набора, так что вам нужно добавить его только один раз в файл? –

+0

Несомненно, я могу определить тестовый разрыв на уровне набора. Но, как я уже упоминал, структура целого набора довольно сложна со множеством вложенных подсетей. Таким образом, любое внутреннее тестовое отключение переопределяет одно из родительского пакета. Для меня немного неудобно добавить ключевое слово захвата в более чем 20 мест и не забывайте в будущем, поэтому я искал способ, как это сделать в одном месте. Да, возможно, это более обходное решение. –

ответ

1

В конце концов, это получилось слушателем библиотеки, как показано ниже. Я должен согласиться с Брайаном: код не короткий и приятный, но он выполняет желаемую цель - одну точку в наборе, где определяется захват экрана. В качестве большого преимущества я вижу возможность захвата снимка экрана для неудачной установки - в некоторых случаях это помогает нам идентифицировать возможные проблемы с инфраструктурой. Обратите внимание на часть с ActionChains - она ​​масштабируется в браузере. В нашем интерфейсном приложении используется частичная прокрутка страниц, и с этим увеличением мы можем видеть больше содержимого внутри этого свитка, что действительно полезно для нас. Результат этого ActionChains отличается для каждого браузера, так что это действительно обходное решение.

#!/usr/bin/python 
# -*- coding: utf-8 -*- 
from Selenium2Library import Selenium2Library 
from selenium.common.exceptions import StaleElementReferenceException, WebDriverException 
import re 


class ExtendedSelenium(Selenium2Library): 
    """ Robot Framework library extending Robot Framework Selenium2Library library. 
    """ 
    ROBOT_LISTENER_API_VERSION = 2 
    DON_NOT_CAPTURE_KEYWORDS = ["Run Keyword And Ignore Error", "Run Keyword And Expect Error", "Run Keyword And Return Status", "Wait Until.*"] 

    def __init__(self, timeout=5.0, implicit_wait=0.0, run_on_failure='', screenshot_root_directory=None): 
     super(ExtendedSelenium, self).__init__(timeout, implicit_wait, run_on_failure, screenshot_root_directory) 
     self.ROBOT_LIBRARY_LISTENER = self 
     self._is_current_keyword_inside_teardown = False 
     self._do_not_capture_parent_keywords_count = 0 
     self._screenshot_was_captured = False 

    def _start_test(self, name, attributes): 
     """ Reset flags at the begin of each test. 
     """ 
     self._do_not_capture_parent_keywords_count = 0 
     self._is_current_keyword_inside_teardown = False 
     self._screenshot_was_captured = False 

    def _start_keyword(self, name, attributes): 
     """ Set keyword flag at the beginning of teardown. 
     If the keyword is one of the 'do not capture keywords' increase _do_not_capture_parent_keywords_count counter. 
     """ 
     if attributes["type"] == "Teardown": 
      self._is_current_keyword_inside_teardown = True 
     if any(kw for kw in self.DON_NOT_CAPTURE_KEYWORDS if re.match(kw, attributes["kwname"])): 
      self._do_not_capture_parent_keywords_count += 1 

    def _end_keyword(self, name, attributes): 
     """If the keyword is one of the 'do not capture keywords' decrease _do_not_capture_parent_keywords_count counter. 
     Capture Screenshot if: 
     - keyword failed AND 
     - test is not in teardown phase AND 
     - the parent keyword isn't one of the 'do not capture keywords' 
     RuntimeError exception is thrown when no browser is open (backend test), no screenshot is captured in this case. 
     """ 
     if any(kw for kw in self.DON_NOT_CAPTURE_KEYWORDS if re.match(kw, attributes["kwname"])): 
      self._do_not_capture_parent_keywords_count -= 1 
     if not attributes["status"] == "PASS" and not self._is_current_keyword_inside_teardown and self._do_not_capture_parent_keywords_count == 0 and not self._screenshot_was_captured: 
      self._screenshot_was_captured = True 
      try: 
       self.capture_page_screenshot() 
       # TODO refactor this so it is reusable and nice! 
       from selenium.webdriver.common.action_chains import ActionChains 
       from selenium.webdriver.common.keys import Keys 
       ActionChains(super(ExtendedSelenium, self)._current_browser()).send_keys(Keys.CONTROL, Keys.SUBTRACT, Keys.NULL).perform() 
       ActionChains(super(ExtendedSelenium, self)._current_browser()).send_keys(Keys.CONTROL, Keys.SUBTRACT, Keys.NULL).perform() 
       self.capture_page_screenshot() 
       ActionChains(super(ExtendedSelenium, self)._current_browser()).send_keys(Keys.CONTROL, '0', Keys.NULL).perform() 
      except RuntimeError: 
       pass 

Любые комментарии могут быть отправлены.

0

Я завернул все в блок try/except для моих тестов. Таким образом, в любой момент, если тест не прошел, снимок экрана находится в исключающем блоке, и я получаю снимок экрана в момент до/после/... что угодно.

try: 
    class UnitTestRunner(): 
     ... 
except: 
    driver.save_screenshot('filepath') 
+0

Это хорошо! Благодарю. –

Смежные вопросы