RECT/Tests
Remote Etersoft CIFS Tester - тесты
Загрузка
Сами файлы тестов (а также документацию) можно получить из git-репозитория http://git.etersoft.ru/people/lbeasty/packages/rect-tests.git/. Если далее читать неинтересно, можно перейти в раздел RECT - Быстрый старт
Состав
Тесты представлены в виде пакета, содержащего следующие файлы:
- конфигурационные файлы с расширением .yaml
- собственно файлы с тестами
Конфигурационный файл
Конфигурационный файл пишется на YAML. Полезные ссылки:
- http://yaml.org
- http://yaml.org/spec/cvs/current.html -- Спецификация YAML.
- http://pyyaml.org/wiki/PyYAMLDocumentation -- документация по использованному модулю Python.
Концептуально, в YAML есть простые типы данных (строки, числа...), коллекции (читай: списки) и структуры (читай: словари)
Корневым элементом конфигурационного файла является словарь. Обязательные элементы:
- shares -- список шар
- slaves -- список slave'ов
Необязательные
- timeout -- таймаут всех операций со slave'ами. Если slave завис, то через
- timeout миллисекунд master получит исключение. По умолчанию таймаут
- бесконечен.
Используемые примерами:
- file -- имя файла создаваемое для тестов. По умолчанию test.dat
- data -- данные, которые будут записаны в файл.
Ещё там лежат настройки тестов. Ключи имеют вид tID[.method], значения -- список словарей. В словарях 2 элемента обязательны: shares и slaves. Тест будет пользоваться именно этими шарами и слейвами. И то и другое -- списки, содержащие имена. Есть еще третий необязательный элемент: mountoptions. Он может быть выполнен в виде строки с опциями монтирования. Тогда эти опции будут использоваться для всех слэйвов для конкретного теста. А может быть выполнен в виде словаря: соответствие опций монтирования для каждого имени слэйва. Дополнительное требование -- длины списков должны соответствовать требованиям теста. Все остальные поля могут использоваться или должны игнорироваться конкретными тестами (есть в поле args соотв. класса, см. ниже).
Всё остальное игнорируется, в том числе и конфигурационные данные отсутствующих тестов.
Проблема: слабая диагностика. Если где-то опечатка, работать ничего не будет (скорее всего), но выяснить, почему, иногда бывает непросто. Возможно, стоит написать процедуру и/или утилиту проверки корректности конфигурационного файла.
Тест
Каждый тест (test case) -- это класс, наследующий RECT.TestCase. У него есть поля:
- n_shares (целое число) -- число шар, требуемых тесту
- n_slaves (целое число) -- число slaves, требуемых тесту
- tID -- идентификатор теста. По умолчанию (если tID не переопределен явно)
- в качестве tID используется имя класса теста. tID используется в
- конфигурационном файле для обозначения теста.
- config -- глобальная конфигурация тестировочной среды (весь конфигурационный
- файл)
- args -- параметры конкретно этого экземпляра теста. Могут быть заданы в
- конфигурационном файле.
Notes:
- ещё у тестов есть метод id(), по умолчанию возвращающий module.class. Это, с
- одной стороны, интересно, с другой -- мне лично очень не нравится видеть в
- конфигах строки вида main.Simple. Возможно, стоит переопределить этот
- метод как-нибудь или игнорировать мои нравится/не нравится, и таким образом
- добиться единообразия и упразнить поле tID.
Методы
У каждого теста есть методы. Средой, в традициях unittest, используются методы, имена которых начинаются на test, или, если таких нет, метод runTest.
Каждый такой метод должен иметь docstring. Первая её строка используется в описании теста.
Ещё у теста есть несколько служебных методов. Один из самых интересных -- shortDecription(...). Он возвращает строку с описанием теста. Она используется, например, unittest.TextTestRunner при отображении результатов.
Ещё есть методы setUp(...) и tearDown(...). Переопределяя их стоит не забывать вызывать методы родительского класса.
Конфигурация для методов
Каждый тест может предоставить один или несколько методов для тестирования. Они могут конфигурироваться отдельно или вместе. Поэтому все тесты одного метода обязаны требовать одинаковое число шар и слейвов.
Пример: пусть у нас есть тест:
class Example(TestCase): """An example""" n_shares = 1 n_slaves = 2 def testSomething(self): """Just test something Bla bla bla """ <...> def testNothing(self): """Do-nothing test.""" pass def testOther(self): """OMG What should I write here?""" <...>
Этот тест может быть сконфигурирован так:
<...> #запустить testOther так: Example.testOther: - shares: [aaa] slaves: [bbb, ccc] mountoptions: option1,option2 #всё остальное -- иначе Example: - slaves: [bbb, ccc] shares: [xxx] mountoptions: bbb: option1 ccc: option2 <...>
Тест testOther не будет запущен для шары xxx!
Замечания по группировке тестов
Выглядит для меня это примерно так:
- Каталог - Файл - Класс - Метод
Как упоминалось, методы одного класса работают с одним числом shares и slaves, и могут вместе конфигурироваться.
Тесты в одном файле удобно запускать вместе.
Тесты в одном каталоге несложно запускать вместе.
Тесты в разных каталогах можно запускать вместе. Но можно это и запретить, тогда они смогут пересекаться по именам (точнее, по идентификаторам тестов).
Запуск тестов
Тесты запускаются либо запуском yaml-файла.
Полное описание результата выполнения тестов выводится на консоль мастера.
Краткое описание выполнено в виде html-страницы, называющейся result_YYYY-MM-DD.html.
Все результаты тестов сохраняются в xml-формате. Возможна последующая обработка представления результатов тестирования.