понедельник, 6 августа 2018 г.

Функционал

Часто в разговоре люди упоминаю Функционал в разрезе функциональных требований/ возможностей системы. Это неправильно.

Оставлю эту ссылку здесь.

pytest BVT часть 2

Как и обещал продолжаю цикл статей про pytest и создание фреймворка для организации BVT.

В прошлой части немного разобрались с терминологией, в этой же более детально опишем, что же будем разрабатывать.

BVT - это базовый набор тестов, который проверяет самое основное, очень часто в это набор уносят тесты, которые проверяют, что называется, целостность сборки. Что будет входить в наш тестовый фреймворк:
  1. Проверка наличия файлов. Удобно для проверки бинарных файлов, логов, конфигов, раскиданных по ФС и т.д. и т.п.
  2. Запрос версии. У каждого исполняемого файла обязательно должна быть версия или подпись. Почему версия удобна и необходима думаю не нужно говорить.
  3. Проверка опций в конфигурационных файлах. Эти проверки избавят от проблем протечки в продакшн конфигов с включенным дебагом. 
  4. Статусы запущенных/зарегистрированных сервисов.
  5. Проверка статусов запущенных программ.
  6. Открытые порты.
  7. Проверка ответов на http запросы. Бывает в сервисы встраивают возможность проверки состояния сервисов (а-ля /healthcheck, /check). Удобно проверить и данную функциональность.
На Линуксе подобные проверки легко решаются использованием bash, на github есть замечательный проект https://github.com/sstephenson/bats, который представляет эту возможность из коробки.

Т.к. нашей целью является изучение pytest, то в качестве основы предлагаю взять таверн https://github.com/taverntesting/tavern. Чем он хорош с точки зрения донорского проекта?
  1. Декларативный конфиг на yaml. Сама по себе декларация очень удобна, она позволит разделить понятия тестового движка и тестов. Соответственно один человек будет заниматься написанием кода, а другой за наполнение тесового плана. Плюс yaml гораздо удобнее и проще относительно json, xml.
  2. Написан на pytest. Можно брать много годных идей, например, cli для прогона тестов.
  3. Для фреймворка написаны свои тесты. Да,да, именно тесты. Фреймворки имеют тенденцию с годами расширяться и усложняться, соответственно нужны регрессионные автотесты.
  4. Ну и куча других плюше - настроенный gitlab-ci, requirements, документация и т.п.
В следующей части набросаем скелет фреймворка и напишем на нем "hello world".

понедельник, 30 июля 2018 г.

pytest BVT часть 1

Поговорим немного о тестировании. Что такое Build Verification Test (BVT/БВТ)?

Найти общего определения на просторах интеренета мне не удалось, поэтому попробую свормулировать сам. 

BVT - это набор базовых тестовых сценариев, нацеленных на выявление явных ошибок. Часто в литературе также под BVT понимают Смок или Дымовое тестирование.

BVT обладают следующими свойствами:
  1. выполнение тестов производится на каждую сборку
  2. высокая скорость исполнение
  3. высокое покрытие базовой функциональности
  4. включают только критичные тестовые сценарии 
Оговорюсь здесь, что описанные выше свойства довольно условные, каждая команда вправе сама устанавливать критерии качества и расширать BVT до нужного ей объема.
Что все это значит для автоматизатора?

Необходимо написать такие автотесты, которые проверят каждую выпускаемую сборку на соотвествие критичным требованиям. Если у команды есть CI, то на основе прохождения BVT делается заключение о пригодности сборки для дальнейшего тестирования.

Примеры автоматических BVT.
  1. Проверка статусов запущенных сервисов.
  2. Наличие в сборке исполняемых и конфигурационных файлов.
  3. Отсутсвие критичных сообщений об ошибках в логах.
  4. и т.п. и т.д.
Разобравшись немного с BVT в следующих частях попробуем написать на pytest небольшой фремворк для разработки универсальных BVT.

воскресенье, 30 октября 2016 г.

Это определение идеально

Есть старый метод исследования систем. Он называется «метод черного ящика». Метод гласит: мы не знаем внутренней структуры системы, но мы можем подать сигнал на ее вход и зафиксировать реакцию на выходе. Сопоставляя определенными методами (методом спектрального анализа, методом решения определенных интегральных уравнений и так далее) функции на входе и выходе, мы можем получить характеристику системы.

вторник, 16 февраля 2016 г.

pytest продолжение

В первой части статей мы немного познакомились с основными базовыми возможностями pytest. Рассмотрели его особенностей и подходы.

В личных беседах и по почте поступил ряд вопросов и предложений, поэтому продолжению быть. В этой и последующих статьях погрузимся глубже в возможности pytest. Новый материал предлагаю выкладывать в виде поваренной книги - проблема, рецептура, ингредиенты, 5 минут готовки, наслаждение.

Последовательно выполнение тестовых сценариев


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

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

Например, тестируемая программа при первом запуске накатывает схему базы (sqlite чтобы не морочиться) и заполняет её некоторой служебной информацией. Допустим перед нами стоит задача "дешево" протестировать этот модуль. Сходу задачу модно разбить на 2 подзадачи - проверка создания файла базы, затем проверка схемы и в конце проверка данных.

Самый простой вариант - нумерация в названии тестов

# conftest.py
import os
import pytest
import sqlite3


def pytest_configure(config):

    config.DB_PATH = "db.sqlite"


@pytest.fixture(scope="module")
def creator(request):
    DB_PATH = request.config.DB_PATH
    con = sqlite3.connect(DB_PATH)
    cur = con.cursor()
    cur.executescript("""
        create table person(
            firstname,
            lastname,
            age
        );

        create table book(
            title,
            author,
            published
        );

        insert into book(title, author, published)
        values (
            'Dirk Gently''s Holistic Detective Agency',
            'Douglas Adams',
            1987
        );
        """)
    con.commit()
    con.close()
    return DB_PATH


@pytest.fixture
def cursor(request):
    class cursor:

        def __init__(self, dbpath):
            self.dbpath = dbpath
            self.conn = sqlite3.connect(self.dbpath)

        def table_exists(self, table):
            cursor = self.conn.cursor()
            cursor.execute(
                "SELECT name FROM sqlite_master WHERE type = \"table\"")
            tables = cursor.fetchall()
            for each in tables:
                if table in each:
                    return True
            return False

        def getrows(self, table):
            cursor = self.conn.cursor()
            cursor.execute("SELECT * FROM %s;" % (table))
            return cursor.fetchall()

    return cursor(request.config.DB_PATH)

# test.py
def test_1_db_exists(creator):
    assert os.path.exists(creator)


@pytest.mark.parametrize("table", ["person", "book"])
def test_2_check_scheme(table, creator, cursor):
    result = cursor.table_exists(table)
    assert result


@pytest.mark.parametrize("table", ["book"])
def test_3_check_rows(table, creator, cursor):
    assert cursor.getrows(table)


Спасибо документации питона за готовые примеры.

У такого подхода есть ряд недостатков.
1. В названии теста появляется нумерация - это лишняя мета информация. (Это может сказаться на тестовом отчете или билд логе CI сервера)
2. Название теста усложняется
3. Вставка нового элемента в середину приведет к смене нумерации всех последующих тестов


Вариант посложнее - маркеры


Свои маркеры мы реализовывать не будем, а используем готовый плагин pytest-ordering. В принципе вся реализация такого плагина составит не больше 100 строчек кода.

# test.py
@pytest.mark.order1
def test_db_exists(creator):
    assert os.path.exists(creator)


@pytest.mark.order2
@pytest.mark.parametrize("table", ["person", "book"])
def test_check_scheme(table, creator, cursor):
    result = cursor.table_exists(table)
    assert result


@pytest.mark.order3
@pytest.mark.parametrize("table", ["book"])
def test_check_rows(table, creator, cursor):
    assert cursor.getrows(table)


Наши тестовые функции преобразились, стали более понимаемы для чтения.
Из коробки плагин содержит создание цепочек выполнения, более понятные маркеры (pytest.mark.run('first'), pytest.mark.run('second')) и прочее. Более подробно в микро доку плагина.

Ссылки
[1] https://docs.python.org/2/library/sqlite3.html
[2] http://pytest-ordering.readthedocs.org/en/develop/