Что пишут в блогах

Подписаться

Очные тренинги

Все очные тренинги
Оставь заявку на тренинг в своем городе

Онлайн-тренинги

  • Все онлайн-курсы
  •  

    http://software-testing.ru/about/authors/9-barancev

    Разделы портала

    VIP-вакансии

    Наши партнёры

    www.it4business.ru

    UML2.ru

    SysIQ Inc.

    Selenium+TestNG: Автоматическое снятие скриншотов при неуспешном прохождении теста
    11.07.2010 12:44

    Автор: Баранцев Алексей

    Слушатели тренинга "Программирование для тестировщиков" часто задают вопросы, на которые я не успеваю ответить ни во время занятий, ни во время консультаций, и которые я рассматриваю как второстепенные, потому что они относятся не к к умению автоматизировать тесты, а к хитрым способам использования того или иного конкретного инструмента.

    Но поскольку вопросы действительно интересные, и поскольку иногда я знаю ответы на них, было бы несправедливо об этом умолчать, поэтому я решил оформить их в виде серии заметок. Как я уже сказал, вдохновение я черпаю из вопросов участников упомянутого выше тренинга, поэтому нетрудно догадаться, что заметки будут посвящены главным образом инструментам Selenium и TestNG. Это будет не систематическое изложение того, как делать тесты, и не документация по использованию инструментов, а небольшие рассказы о некоторых полезных приемах и штучках.

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

    Оригинальная версия SeleneseTestNgHelper

    Если вы когда-нибудь в Selenium IDE указывали "Java (TestNG)" в качестве целевого формата для генерации кода, вы могли видеть заготовку теста приблизительно такого вида:

    package com.example.tests; 
    import com.thoughtworks.selenium.*; 
    import org.testng.annotations.*;
    import static org.testng.Assert.*;
    import java.util.regex.Pattern;
    public class Untitled extends SeleneseTestNgHelper { 
        @Test
    public void testUntitled() throws Exception {
        }
    }

    Но если вы попробуете перенести этот код в среду разработки и скомпилировать его, вас постигнет разочарование – класса SeleneseTestNgHelper нет ни в Selenium RC, ни в TestNG. На официальных сайтах Selenium и TestNG он тоже не упоминается и загрузить его оттуда нельзя.

    Тем не менее, при желании этот класс можно найти, как в уже скомпилированном виде, так и в исходном коде. Чтобы использовать его, достаточно помимо Selenium RC подключить ещё дополнительную библиотеку selenium-java-testng-helper-1.0.1.jar.

    А, собственно, причём тут этот класс? Ведь я обещал рассказать про автоматическое снятие скриншотов при неуспешном прохождении теста? Всё верно, дело в том, что SeleneseTestNgHelper как раз и содержит реализацию этой функциональности! Просто добавьте вышеуказанную библиотеку в ваш проект, унаследуйте тесты от класса SeleneseTestNgHelper – и всё.

    Впрочем, нет, не всё.

    Улучшенная версия SeleneseTestNgHelper

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

    Далее – описание того, чем мой вариант SeleneseTestNgHelper отличается (в лучшую сторону, конечно :) ) от того, ссылка на который приведена выше.

    1. Оригинальное расширение использует для снятия скриншотов второй экземпляр Selenium, а не тот, который управляет тестируемым приложением. И вовсе не потому, что так лучше, а потому, что когда разрабатывался SeleneseTestNgHelper, не существовало честного способа переиспользовать тот же самый экземпляр Selenium.

    Такая возможность появилась лишь относительно недавно с появлением в TestNG нового интерфейса IInvokedMethodListener2 (он пока ещё не описан в официальной документации, но можно найти его описание в javadoc).

    Соответственно, я переписал ScreenshotListener так, чтобы он реализовывал именно этот новый интерфейс и использовал для снятия скриншотов тот же самый экземпляр Selenium.

    Чем это лучше? Во-первых, это позволяет вывести на передний план и развернуть окно браузера перед снятием скриншота, вызвав методы selenium.windowFocus() и selenium.windowMaximize(). Во-вторых, это даёт возможность использовать способ снятия скриншота не со всего экрана, а со страницы приложения, включая невидимые части, требующие скроллирования (впрочем, об этом, как я и обещал, расскажу в другой заметке).

    2. Оригинальное расширение содержит жестко прописанный в коде механизм подключения ScreenshotListener. Более правильным способом является использование внешних методов подключения "слушателей" (listeners) – в командной строке, конфигурационном файле или в аннотации @Listeners.

    Поэтому я удалил абсолютно ненужный метод attachScreenshotListener, а для обратной совместимости добавил классу SeleneseTestNgHelper аннотацию @Listeners({ScreenshotListener.class}). В результате автоматическое снятие скриншотов будет включено у всех тестов, которые наследуются от класса SeleneseTestNgHelper.

    Кстати, такая замена жестко закодированного подключения на аннотацию тоже стала возможна лишь после того, как совсем недавно в TestNG стало возможно указывать аннотацию @Listeners у базового класса, раньше это нужно было делать у каждого тестового класса отдельно (либо использовать конфигурационный файл).

    Конечно, эту аннотацию в классе SeleneseTestNgHelper тоже можно считать жестко закодированной. Но ещё раз подчёркиваю – она там оставлена для обеспечения обратной совместимости с предыдущей версией. А если вы хотите включать слушатель ScreenshotListener только для отдельных тестов, либо включать разные слушатели для разных тестов, тогда вам нужно в исходном коде класса SeleneseTestNgHelper удалить аннотацию @Listeners (то есть полностью) и сделать свои собственные настройки. Я не стал делать отдельную скомпилированную версию с отключенным слушателем, желающие обеспечить большую гибкость могут взять исходный код и доработать его самостоятельно.

    Напоследок следует отметить, что сейчас в рамках Selenium 2.0 разрабатывается новая версия SeleneseTestNgHelper, оптимизированная для использования с новым движком WebDriver, а данная версия предлагается всем тем, кто использует сейчас и собирается продолжать использовать Selenium 1.x.

    Ссылки

    Скомпилированная библиотека: selenium-java-testng-helper-1.1.jar
    Проект Eclipse, содержащий исходный код: SeleniumScreenshoots.zip

    Обсудить в форуме

     
    Комментарии (3)
    Screenshot in FireFox
    1 12.07.2010 15:55
    Ян Алексеенко
    Столкнувшись с подобной проблемой, я нашел оригинальное решение для FireFox не используя сторонних библиотек, один JS. Вот пример получения screenshot'a объекта на странице по его xpath (Работает в Selenium RC & IDE):

    var elementLeftX = ...;
    var elementTopY = ...;
    var elementWidth = ...;
    var elementHeight = ...;
    var grabber = { prepareCanvas: function(width, height) {
    var styleWidth = width + 'px';
    var styleHeight = height + 'px';
    var grabCanvas = document.getElementById('screenshot_canvas');
    if (!grabCanvas) {
    var ns = 'http://www.w3.org/1999/xhtml';
    grabCanvas = document.createElementNS(ns, 'html:canvas');
    grabCanvas.id = 'screenshot_canvas';
    grabCanvas.style.display = 'none';
    document.documentElement.appendChild(grabCanvas);
    }
    grabCanvas.width = width;
    grabCanvas.style.width = styleWidth;
    grabCanvas.style.maxWidth = styleWidth;
    grabCanvas.height = height;
    grabCanvas.style.height = styleHeight;
    grabCanvas.style.maxHeight = styleHeight;
    return grabCanvas;
    }, prepareContext: function(canvas, box) {
    var context = canvas.getContext('2d');
    context.clearRect(box.x, box.y, box.width, box.height);
    context.save();
    return context;
    }
    };
    var window = this.browserbot.getCurrentWindow();
    var doc = window.document.documentElement;
    var box = {
    x: elementLeftX,
    y: elementTopY,
    width: elementWidth,
    height: elementHeight
    };
    var format = 'png';
    var canvas = grabber.prepareCanvas(box.width, box.height);
    var context = grabber.prepareContext(canvas, box);
    context.drawWindow(window, box.x, box.y, box.width, box.height,
    'white');
    context.restore();
    var dataUrl = canvas.toDataURL(\"image/\" + format);
    dataUrl;

    dataUrl - Содержит Base64 String после ее декодирования можно создать файл и сохранить изображение локатора.
    КАК СДЕЛАТЬ СКРИНШОТ, ИСПОЛЬЗУЯ ТОЛЬКО JAVA
    2 13.07.2010 12:01
    ABVgedeika
    Вот здесь пример для создания скриншотов на JAVA

    http://qa-room.com/index.php?option=com_content&view=article&id=42:-java&catid=37:selenium-rc&Itemid=54

    Расширив его, можно добавить такие фичи, как логирование в отчет, ипользуя линки на скриншот, создание скриншотов для отдельных ассертов и т.д.
    Re: КАК СДЕЛАТЬ СКРИНШОТ, ИСПОЛЬЗУЯ ТОЛЬКО JAVA
    3 13.07.2010 14:19
    Ян Алексеенко
    К сожалению, ваш подход будет работать только если Selenium server запущен на одной машине с client'ом. Это слишком сильно ограничивает некоторые преимущества распределенного запуска. Для общего screenshot'а лучше использовать встроенный в селениум метод captureScreenshotToString() (полный аналог Java Robot но исполняется на машине с запущенным Selenium Server'ом).

    Добавьтe Ваш комментарий

    Ваше имя (псевдоним):
    Ваш адрес почты:
    Заголовок:
    Комментарий: