Автоматизированное тестирование ПО

Материал из Rosalab Wiki
Версия от 12:56, 31 мая 2013; Euspectre (обсуждение | вклад) (Prepared the first tutorial (writing a simple test))

Это снимок страницы. Он включает старые, но не удалённые версии шаблонов и изображений.
Перейти к: навигация, поиск

Система автоматизированного тестирования приложений для ROSA Linux позволяет проверять различные сценарии работы этих приложений, имитируя действия пользователя, такие, как:

  • ввод с клавиатуры;
  • перемещение мыши, нажатие кнопок мыши.

Исходный код системы: https://abf.rosalinux.ru/spectre/rosa-autotest/

Система является надстройкой над Python unit testing framework. Также система включает в себя модифицированную версию инструмента Xpresser.

Тестирование графических приложений

Тесты графических приложений для ROSA Linux могут работать в двух режимах:

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

Тесты для приложений в установленной системе, как правило, стоит писать так, чтобы один и тот же тест можно было запустить в любом их указанных режимов. Это получается автоматически, если тест использует только средства Python unittest и API, предоставляемый нашей системой.

Система тестирования использует Python 2.7.

Тестирование приложений, запущенных в виртуальной машине

Примечание. Для большинства разработчиков тестов, скорее всего, будет удобнее запускать тесты не в этом режиме, а в локальном (см. ниже).

Инструкции по установке и настройке всего необходимого для этого режима тестирования находятся здесь: https://abf.rosalinux.ru/spectre/rosa-autotest/tree/master/doc

Скрипт для запуска всего набора тестов: launcher.py

Тестирование приложений, запущенных на локальной машине

Здесь предполагается, что тестирование выполняется на ROSA Desktop Fresh.

  • Для начала стоит установить необходимое ПО:
# urpmi git python-distribute python-xlib opencv-devel python-opencv python-numpy python-imaging scrot
# easy_install pyuserinput
  • Также потребуется приложение, в котором можно будет подготовить изображения для тестов. Можно использовать, например, GIMP.
  • Загрузить самую свежую версию системы тестирования можно из git-репозитория:
$ git clone https://abf.rosalinux.ru/spectre/rosa-autotest.git

Допустим, система загружена в каталог /home/user/rosa-autotest.

Чтобы python нашёл нужные модули при запуске тестов, можно создать ссылки на их каталоги в /usr/lib/python2.7/site-packages/ (от имени root):

# ln -s /home/user/rosa-autotest/rosa_autotest /usr/lib/python2.7/site-packages/
# ln -s /home/user/rosa-autotest/rosatest /usr/lib/python2.7/site-packages/
# ln -s /home/user/rosa-autotest/xpresser /usr/lib/python2.7/site-packages/

Путь к модулям также можно задать с помощью переменной среды PYTHONPATH.

Проверить, что все необходимые пути указаны правильно, можно, загрузив Python и попробовав импортировать модули, например, так:

$ python -c "import rosa_autotest, rosatest, xpresser"

Если эта команда отработает без ошибок, значит, всё в порядке.

Подготовка тестов (tutorial №1)

Здесь предполагается, что разработчик тестов владеет Python хотя бы на базовом уровне (см. http://docs.python.org/2.7/tutorial/index.html).

Для примера подготовим тест, который запускает Firefox, открывает новую вкладку и переходит на какой-либо сайт. Все действия в данном случае выполняются на ROSA Desktop Fresh c KDE.

Создадим файл test_firefox.py, а также - подкаталог images в том же каталоге. В images будут храниться изображения, используемые тестом.

Допустим, перед началом работы теста рабочий стол выглядит так:

Rosa autotest scr1.png

Чтобы запустить Firefox, достаточно кликнуть его значок. Чтобы тест мог это сделать автоматически, сделаем снимок соотв. части экрана (или можно сделать полный снимок экрана и вырезать этот значок оттуда):

Rosa autotest ff start.png

Сохраним это изображение в файле ff-start.png в каталоге images

Откроем test_firefox.py в каком-либо текстовом редакторе и напишем там следующее:

import time
import rosatest

class TestFirefox(rosatest.TestCaseInstalled):
    """Tests for Firefox"""

    @rosatest.imagebased
    def test_ff(self):
        """A simple test"""
        self.load_images("images")

        self.click("ff-start")

В начале этого файла загружаются необходимые модули, затем определяется класс TestFirefox, наследник класса rosatest.TestCaseInstalled.

Классы-наследники rosatest.TestCaseInstalled используются для тестов ПО на установленной системе, наследники rosatest.TestCaseLive - на системе, загруженной в Live-режиме.

Так же, как и при работе Python unittest, в классе стоит определить одну или более функций, каждая из которых выполняет свой тест в составе данного test case. В данном случае это test_ff(). Тестовые функции, использующие поиск изображений и имитацию действий пользователя, нужно отметить декоратором @rosatest.imagebased.

self.load_images("images") загружает изображения, которые будут использоваться в тесте, из созданного нами выше подкаталога images.

self.click("ff-start") ищет на экране изображение из файла images/ff-start.png и имитирует нажатие левой кнопкой мыши в соотв. месте.

На этом этапе уже можно запустить тест и проверить, что он, действительно, запускает Firefox. Проще всего для этого использовать скрипт local.py (обратите внимание, что при этом логи теста будут сохранены в подкаталоге results текущего каталога):

python /home/user/rosa-autotest/rosatest/local.py <путь к test_firefox.py>

В результате должен запуститься Firefox:

Rosa autotest scr2.png

В консоль при этом будет выведено следующее:

== Starting test test_firefox.TestFirefox.test_ff ==

Ran 1 test
OK

Примечание. В качестве идентификатора теста используется строка имя_файла.имя_класса.имя_функции. При запуске с помощью local.py результаты теста сохраняются в подкаталоге results/имя_файла/имя_класса/имя_функции текущего каталога. Также используется подкаталог tmp/имя_файла/имя_класса/имя_функции - для хранения временных файлов при работе теста.

Пока тест всего лишь запускает Firefox, но не проверяет, успешно ли этот браузер запустился. Можно попробовать проверить, например, появилась ли на экране кнопка перехода на домашнюю страницу (Rosa autotest ff home button.png).

Сделаем снимок соотв. части экрана и сохраним изображение этой кнопки в images/ff-home-button.png. Затем добавим в функцию test_ff() следующее:

        self.wait("ff-home-button")

wait() ждёт пока на экране не появится указанное изображение. Если изображение появилось, выполнение теста продолжается, если же оно не появилось в течение заданного времени (по умолчанию, 30 секунд), wait() генерирует исключение, тест завершается и отмечается как failed.

Максимальное время ожидания (в секундах) можно задать в параметре timeout, а время между последовательными проверками, появилось ли изображение, - в параметре interval, например:

        self.wait("ff-home-button", timeout=120, interval=5)

Если изображение за заданное время на экране не появилось, тест завершится с ошибкой:

== Starting test test_firefox.TestFirefox.test_ff ==

==============================
FAIL: test_ff (test_firefox.TestFirefox)
A simple test
------------------------------
Traceback (most recent call last):
  File "/usr/lib/python2.7/site-packages/rosatest/test.py", line 349, in internal
    func(self, *args, **kwargs)
  File "/home/eugene/work/tutorial/test_firefox.py", line 13, in test_ff
    self.wait("ff-home-button", timeout=1)
  File "/usr/lib/python2.7/site-packages/rosatest/test.py", line 299, in wait
    match, "Failed to find an image on the screen: " + image)
AssertionError: Failed to find an image on the screen: ff-home-button

Ran 1 test
FAILED (failures=1)

При завершении теста с ошибкой в каталог с результатами теста автоматически сохраняется снимок экрана на этот момент. Это может помочь при анализе результатов тестов. В логе теста (test.log в каталоге с результатами) также может быть полезная информация, в т.ч. сообщения, которые выводил непосредственно тест.

Примечание. Система тестирования использует стандартные assertions из Python unittest. TestCase-классы из модуля rosatest являются наследниками unittest.TestCase, так что в тестах можно использовать средства unittest и явно.

Пусть теперь тест откроет в Firefox новую вкладку, нажав на Rosa autotest ff new tab.png (это изображение нужно сохранить в images/ff-new-tab.png), и введёт там адрес "www.rosalab.com". Для этого добавим в функцию test_ff() следующее:

        self.click("ff-new-tab")

        # Wait a little for the tab to open.
        time.sleep(1)

        self.type_string("www.rosalab.com")

Остаётся нажать на "Enter" и подождать пока Firefox не откроет указанный сайт, точнее, пока где-то на экране не появится такое изображение:

Rosa autotest rosa logo.png

Код:

        self.press_key("enter")
        self.wait("rosa-logo")

В результате должен открыться сайт "www.rosalab.com":

Rosa autotest scr3.png

Теперь можно закрыть Firefox. Тест может имитировать нажатие комбинации клавиш "alt-f4":

        self.press_key("alt-f4")

Примечание. С помощью press_key() можно имитировать нажатия и отдельных клавиш ("esc", "f4" и пр.), и их комбинаций. Комбинации клавиш записываются через дефис ("ctrl-alt-v", "shift-f7", "ctrl-a" и пр.). Список обозначений клавиш приведён здесь: http://en.wikibooks.org/wiki/QEMU/Monitor#sendkey_keys, единственное дополнение - для клавиши "Enter" можно использовать как обозначение "ret", так и "enter".

Стоит учесть, что Firefox при закрытии может выдать предупреждение о том, что закрывается несколько вкладок (а может и не выдать):

Rosa autotest scr4.png

В тесте можно, например, проверить, появилась ли на экране кнопка Rosa autotest ff close tabs.png (изображение - images/ff-close-tabs.png), и если появилась, нажать её:

        button = self.find("ff-close-tabs", timeout=5)
        if button:
            self.click(button)

Функция find() делает почти то же самое, что и wait(). Отличие одно: если изображение не найдено на экране, find() возвращает None и исключений не выбрасывает (т.е. тест при этом не считается failed).

Если изображение на экране найдено, find() возвращает объект, который можно передать в функции click(), right_click(), double_click() и т.д. вместо имени изображения, что и продемонстрировано выше.

В итоге получился такой тест:

import time
import rosatest

class TestFirefox(rosatest.TestCaseInstalled):
    """Tests for Firefox"""

    @rosatest.imagebased
    def test_ff(self):
        """A simple test"""
        self.load_images("images")

        self.click("ff-start")
        self.wait("ff-home-button")

        self.click("ff-new-tab")

        # Wait a little for the tab to open.
        time.sleep(1)

        self.type_string("www.rosalab.com")
        self.press_key("enter")
        self.wait("rosa-logo")

        self.press_key("alt-f4")

        button = self.find("ff-close-tabs", timeout=5)
        if button:
            self.click(button)

TODO: тест на работу с файлами