Есть старый метод исследования систем. Он называется «метод черного ящика». Метод гласит: мы не знаем внутренней структуры системы, но мы можем подать сигнал на ее вход и зафиксировать реакцию на выходе. Сопоставляя определенными методами (методом спектрального анализа, методом решения определенных интегральных уравнений и так далее) функции на входе и выходе, мы можем получить характеристику системы.
воскресенье, 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/
В личных беседах и по почте поступил ряд вопросов и предложений, поэтому продолжению быть. В этой и последующих статьях погрузимся глубже в возможности 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/
суббота, 6 февраля 2016 г.
Топ 10 вопросов по python на stackoverflow
What does the yield keyword do in Python?
What is a metaclass in Python?
How to check whether a file exists using Python
Does Python have a ternary conditional operator?
Calling an external command in Python
How can I make a chain of function decorators in Python?
What does `if __name__ == “__main__”:` do?
How can I merge two Python dictionaries in a single expression?
Sort a Python dictionary by value
How do I install pip on Windows?
Довольно ожидаемо
[1] stackoverflow.com
What is a metaclass in Python?
How to check whether a file exists using Python
Does Python have a ternary conditional operator?
Calling an external command in Python
How can I make a chain of function decorators in Python?
What does `if __name__ == “__main__”:` do?
How can I merge two Python dictionaries in a single expression?
Sort a Python dictionary by value
How do I install pip on Windows?
Довольно ожидаемо
[1] stackoverflow.com
пятница, 29 января 2016 г.
Подписаться на:
Сообщения (Atom)