http://aosabook.org/en/index.html - неплохие статьи об архитекруре приложений с открытым исходным кодом. git, mercurial, nginx, zeromq и проч. А также есть что почитать для тех кто пишет на питоне - Twisted, SQLAlchemy.
понедельник, 16 июня 2014 г.
Часть 3. Совсем немного о py.test.exe
py.test.exe это тул призванный упростить запуск тестов. Оговорюсь сразу что в мою задачу не входит перевод документации, поэтому ознакомится с полным набором команд можно, выполнив в командной строке следующую комманду (да и он может различаться в зависимости от того какие установлены плагины) и пройти по сслылкам в конце поста.
>>> py.test -h
-v - увеличивает детализацию о выполнении теста
--capture - параметр для управлением захвата вывода stdout/stderr. Принимает одно из значений fd|sys|no. Более подробно в ссылках
-s - маска для --capture=no. Параметр удобен, если нужно убрать мусор (например, дебажные принты) из информации о выполнившихся тестах.
--tb - отвечает за детализацию вывода трейса. Одно из long/short/line/native/no
--maxfail=<fail count> - задает максимальное число фейлов, тест удобен при дебаге или если заранее известно что результат тестов будет один и тотже
-x - маска дял --maxfaile=1
--pdb - стартует питоновский дебагер для отладки ошибок. Удобен для отладки тестов (подробнее в одном из следующих постов о дебаге тестов)
import py.test
@py.test.mark.parametrize('num', [i for i in range(5)])
def test_func(num):
print('\ntest_func()')
assert num % 2
def test_fail():
print('bla, bla, fail')
assert False
Выполняем в консоли
>>>py.test use_tool.py -k "test_func" -v -s -x --tb=line
============================= test session starts =============================
platform win32 -- Python 2.7.5 -- py-1.4.20 -- pytest-2.5.2 -- C:\Python27\python.exe
plugins: teamcity-messages
collected 6 items
use_tool.py:37: test_func[0]
test_func()
FAILED
================================== FAILURES ===================================
use_tool.py:40: assert (0 % 2)
!!!!!!!!!!!!!!!!!!! Interrupted: stopping after 1 failures !!!!!!!!!!!!!!!!!!!!
===================== 1 tests deselected by '-ktest_func' =====================
=================== 1 failed, 1 deselected in 0.04 seconds ====================
[2] http://pytest.org/latest/customize.html?highlight=maxfail
[3] http://pytest.org/latest/usage.html
>>> py.test -h
Команды формирования вывода
-q - уменьшает детализацию информации о выполнении теста-v - увеличивает детализацию о выполнении теста
--capture - параметр для управлением захвата вывода stdout/stderr. Принимает одно из значений fd|sys|no. Более подробно в ссылках
-s - маска для --capture=no. Параметр удобен, если нужно убрать мусор (например, дебажные принты) из информации о выполнившихся тестах.
--tb - отвечает за детализацию вывода трейса. Одно из long/short/line/native/no
Команды запуска
-k <test name> - выполнить лишь заданный тест--maxfail=<fail count> - задает максимальное число фейлов, тест удобен при дебаге или если заранее известно что результат тестов будет один и тотже
-x - маска дял --maxfaile=1
--pdb - стартует питоновский дебагер для отладки ошибок. Удобен для отладки тестов (подробнее в одном из следующих постов о дебаге тестов)
Комманды для настройки
--color (yes|no|auto) - цветной вывод в консоли или нетСовсем небольшой пример
# use_tool.pyimport py.test
@py.test.mark.parametrize('num', [i for i in range(5)])
def test_func(num):
print('\ntest_func()')
assert num % 2
def test_fail():
print('bla, bla, fail')
assert False
Выполняем в консоли
>>>py.test use_tool.py -k "test_func" -v -s -x --tb=line
============================= test session starts =============================
platform win32 -- Python 2.7.5 -- py-1.4.20 -- pytest-2.5.2 -- C:\Python27\python.exe
plugins: teamcity-messages
collected 6 items
use_tool.py:37: test_func[0]
test_func()
FAILED
================================== FAILURES ===================================
use_tool.py:40: assert (0 % 2)
!!!!!!!!!!!!!!!!!!! Interrupted: stopping after 1 failures !!!!!!!!!!!!!!!!!!!!
===================== 1 tests deselected by '-ktest_func' =====================
=================== 1 failed, 1 deselected in 0.04 seconds ====================
Ссылки
[1] http://pytest.org/latest/capture.html[2] http://pytest.org/latest/customize.html?highlight=maxfail
[3] http://pytest.org/latest/usage.html
среда, 11 июня 2014 г.
Часть 2. Фикстуры pytest
Всем привет
В первой части немного познакомились с фреймворком для тестирования py.test, а в этой немного углубимся и посмотрим на дополнительные инструменты py.test.
В py.test предусмотрены следующие типы фикстур: встроенные фикстуры, вспомогательные функции, декораторы
setup_module(module)
teardown_module(module)
Это функции которые вызываются перед и после выполнения всех тестов (в прошлой части более подробно об организации тестов)
Данную пару удобно использовать когда подготовка флоу происходит однажды - перед запуском всех тестов.
setup_function(function)
teardown_function(function)
Делают тоже самое что и предыдущие функции, с единственным исключением - функции вызываются перед/после каждым выполнением всех тестовых сценариев.
Рассмотрим небольшой надуманный пример, для понимания механизма
#fixtures.py
def setup_module(module):
print('\nsetup_module()')
def teardown_module(module):
print('\nteardown_module()')
def setup_function(function):
print('\nsetup_function()')
def teardown_function(function):
print('\nteardown_function()')
def test_first():
print('\ntest_first()')
def test_second():
print('\ntest_second()')
class TestMyClass:
@classmethod
def setup_class(cls):
print ('\nsetup_class()')
@classmethod
def teardown_class(cls):
print ('teardown_class()')
def setup_method(self, method):
print ('\nsetup_method()')
def teardown_method(self, method):
print ('\nteardown_method()')
def test_first(self):
print('test_first()')
def test_second(self):
print('test_second()')
>>>py.test -s -v fixtures.py
============================= test session starts =============================
platform win32 -- Python 2.7.5 -- py-1.4.20 -- pytest-2.5.2 -- C:\Python27\python.exe
collected 4 items
fixtures.py:17: test_first
setup_module()
setup_function()
test_first()
PASSED
teardown_function()
fixtures.py:21: test_second
setup_function()
test_second()
PASSED
teardown_function()
fixtures.py:40: TestMyClass.test_first
setup_class()
setup_method()
test_first()
PASSED
teardown_method()
fixtures.py:43: TestMyClass.test_second
setup_method()
test_second()
PASSED
teardown_method()
teardown_class()
teardown_module()
========================== 4 passed in 0.02 seconds ===========================
>>>py.test --fixtures
Для ознакомления в данном посте рассмотри одну из встроенных фикстур tempdir
temdir
Очень полезная вещь, предназначена для работы с темповыми данными. Т.е. в темповой директории можно хранить любые временные файлы. Например, это могут быть логи тестируемых программ или какой-то контекcт теста, который может понадобиться для воспроизведения бага.
Использовать крайне просто
#fixtures.py
def test_file(tmpdir):
f = tmpdir.mkdir('logs').join('test.log')
print(tmpdir.strpath)
f.write('bla bla')
with open(f.strpath, 'r') as fp:
print(fp.read())
>>>py.test -s -v fixtures.py
============================= test session starts =============================
platform win32 -- Python 2.7.5 -- py-1.4.20 -- pytest-2.5.2 -- C:\Python27\python.exe
collected 1 items
fixtures.py:161: test_file \temp\pytest-76\test_file0
bla bla
PASSED
========================== 1 passed in 0.03 seconds ===========================
#fixtures.py
@py.test.mark.parametrize('num', [i for i in range(2)])
def test(num):
assert num % 2
Для определения собственных инструментов в py.test предусмотрены
#fixtures.py
@pytest.fixture(scope="function")
def before(request):
print('\nbefore()')
def after():
print("\nafter()")
request.addfinalizer(after)
def test_func(before):
print("\ntest_func()")
>>>py.test -s -v fixtures.py
============================= test session starts =============================
platform win32 -- Python 2.7.5 -- py-1.4.20 -- pytest-2.5.2 -- C:\Python27\python.exe
collected 1 items
fixtures.py:14: test_func
before()
test_func()
PASSED
after()
========================== 1 passed in 0.01 seconds ===========================
2. Сокращает время разработки теста
3. делает тест прозрачнее
4. Уменьшает количество копипаста
http://en.wikipedia.org/wiki/Test_fixture
http://pythontesting.net/
В первой части немного познакомились с фреймворком для тестирования py.test, а в этой немного углубимся и посмотрим на дополнительные инструменты py.test.
Что такое test fixtures
В тестировании обычно под этим понимают флоу теста, его контекст.В py.test предусмотрены следующие типы фикстур: встроенные фикстуры, вспомогательные функции, декораторы
setup/teardown
Часто перед запуском теста нужно провести базовые подготовления. Например, это может быть настройка окружения, запуск тестовых сервисов, подготовка тестовых данных, инициализация соединения с базами и проч. Для выполнения этих операций в py.test входит небольшой набор вспомогательных функций - несколько пар setup/teardown.setup_module(module)
teardown_module(module)
Это функции которые вызываются перед и после выполнения всех тестов (в прошлой части более подробно об организации тестов)
Данную пару удобно использовать когда подготовка флоу происходит однажды - перед запуском всех тестов.
setup_function(function)
teardown_function(function)
Делают тоже самое что и предыдущие функции, с единственным исключением - функции вызываются перед/после каждым выполнением всех тестовых сценариев.
Рассмотрим небольшой надуманный пример, для понимания механизма
#fixtures.py
def setup_module(module):
print('\nsetup_module()')
def teardown_module(module):
print('\nteardown_module()')
def setup_function(function):
print('\nsetup_function()')
def teardown_function(function):
print('\nteardown_function()')
def test_first():
print('\ntest_first()')
def test_second():
print('\ntest_second()')
class TestMyClass:
@classmethod
def setup_class(cls):
print ('\nsetup_class()')
@classmethod
def teardown_class(cls):
print ('teardown_class()')
def setup_method(self, method):
print ('\nsetup_method()')
def teardown_method(self, method):
print ('\nteardown_method()')
def test_first(self):
print('test_first()')
def test_second(self):
print('test_second()')
>>>py.test -s -v fixtures.py
============================= test session starts =============================
platform win32 -- Python 2.7.5 -- py-1.4.20 -- pytest-2.5.2 -- C:\Python27\python.exe
collected 4 items
fixtures.py:17: test_first
setup_module()
setup_function()
test_first()
PASSED
teardown_function()
fixtures.py:21: test_second
setup_function()
test_second()
PASSED
teardown_function()
fixtures.py:40: TestMyClass.test_first
setup_class()
setup_method()
test_first()
PASSED
teardown_method()
fixtures.py:43: TestMyClass.test_second
setup_method()
test_second()
PASSED
teardown_method()
teardown_class()
teardown_module()
========================== 4 passed in 0.02 seconds ===========================
Встроенные фикстуры
В py.test предусмотрен обширный набор встроенных фикстур с полным набором можно ознакомиться, выполнив в консоле следующую команду>>>py.test --fixtures
Для ознакомления в данном посте рассмотри одну из встроенных фикстур tempdir
temdir
Очень полезная вещь, предназначена для работы с темповыми данными. Т.е. в темповой директории можно хранить любые временные файлы. Например, это могут быть логи тестируемых программ или какой-то контекcт теста, который может понадобиться для воспроизведения бага.
Использовать крайне просто
#fixtures.py
def test_file(tmpdir):
f = tmpdir.mkdir('logs').join('test.log')
print(tmpdir.strpath)
f.write('bla bla')
with open(f.strpath, 'r') as fp:
print(fp.read())
>>>py.test -s -v fixtures.py
============================= test session starts =============================
platform win32 -- Python 2.7.5 -- py-1.4.20 -- pytest-2.5.2 -- C:\Python27\python.exe
collected 1 items
fixtures.py:161: test_file \temp\pytest-76\test_file0
bla bla
PASSED
========================== 1 passed in 0.03 seconds ===========================
Полезные фикстуры
Для итерации по входным данным можно использовать полезный декоратор py.test.mark.parametrize#fixtures.py
@py.test.mark.parametrize('num', [i for i in range(2)])
def test(num):
assert num % 2
py.test -s -v fixtures.py
============================= test session starts =============================
platform win32 -- Python 2.7.5 -- py-1.4.20 -- pytest-2.5.2 -- C:\Python27\python.exe
collected 2 items
fixtures.py:182: test[0] FAILED
fixtures.py:182: test[1] PASSED
================================== FAILURES ===================================
___________________________________ test[0] ___________________________________
num = 0
@py.test.mark.parametrize('num', [i for i in range(2)])
def test(num):
> assert num % 2
E assert (0 % 2)
fixtures.py:184: AssertionError
===================== 1 failed, 1 passed in 0.02 seconds ======================
Кастомизация
О кастомных фикстурах более подробно в одном из следующих постов, поэтому здесь совсем небольшой пример.
#fixtures.py
@pytest.fixture(scope="function")
def before(request):
print('\nbefore()')
def after():
print("\nafter()")
request.addfinalizer(after)
def test_func(before):
print("\ntest_func()")
>>>py.test -s -v fixtures.py
============================= test session starts =============================
platform win32 -- Python 2.7.5 -- py-1.4.20 -- pytest-2.5.2 -- C:\Python27\python.exe
collected 1 items
fixtures.py:14: test_func
before()
test_func()
PASSED
after()
========================== 1 passed in 0.01 seconds ===========================
Вывод
1. Прежде всего это создано для удобства (как собственно и весь py.test)2. Сокращает время разработки теста
3. делает тест прозрачнее
4. Уменьшает количество копипаста
Ссылки
http://pytest.org/latest/http://en.wikipedia.org/wiki/Test_fixture
http://pythontesting.net/
среда, 4 июня 2014 г.
Понимаем UnboundLocalError
Опять же на programmingwats.tumblr.com наткнулся на небольшую особенность питона.
my_str_1 = "1: outside of func"
my_str_2 = "2: outside of func"
def func_1():
my_str_1 = "1: inside the func"
my_str_2 = "2: inside the func"
def func_2():
print(my_str_1)
print(my_str_2)
my_str_1 = "1: inside the class"
func_2()
func_1()
prints:
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
File “<stdin>”, line 8, in func_1
File “<stdin>”, line 5, in func_2
UnboundLocalError: local variable ‘my_str_1’ referenced before assignment
В принципе на эту тему написано довольно много постов и погуглив можно спокойно найти объяснение. Но т.к. в свое время эта особенность питона попила у меня много кровушки я решил написать небольшой пост.
В чем причина такого поведения?
Причина заключается в том что питон преобразует переменную my_str_1 в локальную для func_2 и во время вызова функции print получает на вход не инициализированную переменную.
Решения проблемы тривиальные - либо убрать print, либо изменить название переменной, или объявить my_str_1 как глобальную.
Кто хочет более подробно ознакомиться с причинами такого поведения см ссылки, особенно с [2]
[2]http://eli.thegreenplace.net/2011/05/15/understanding-unboundlocalerror-in-python/
[3]http://programmingwats.tumblr.com/page/2
my_str_1 = "1: outside of func"
my_str_2 = "2: outside of func"
def func_1():
my_str_1 = "1: inside the func"
my_str_2 = "2: inside the func"
def func_2():
print(my_str_1)
print(my_str_2)
my_str_1 = "1: inside the class"
func_2()
func_1()
prints:
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
File “<stdin>”, line 8, in func_1
File “<stdin>”, line 5, in func_2
UnboundLocalError: local variable ‘my_str_1’ referenced before assignment
В принципе на эту тему написано довольно много постов и погуглив можно спокойно найти объяснение. Но т.к. в свое время эта особенность питона попила у меня много кровушки я решил написать небольшой пост.
В чем причина такого поведения?
Причина заключается в том что питон преобразует переменную my_str_1 в локальную для func_2 и во время вызова функции print получает на вход не инициализированную переменную.
Решения проблемы тривиальные - либо убрать print, либо изменить название переменной, или объявить my_str_1 как глобальную.
Кто хочет более подробно ознакомиться с причинами такого поведения см ссылки, особенно с [2]
Ссылки
[1]https://docs.python.org/2/faq/programming.html#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value[2]http://eli.thegreenplace.net/2011/05/15/understanding-unboundlocalerror-in-python/
[3]http://programmingwats.tumblr.com/page/2
вторник, 3 июня 2014 г.
python 2 утечка переменных цикла
Проглядывая programmingwats.tumblr.com нашел небольшую особенность python 2.
Посмотрим на пример:
>>>x = "top"
>>>print(list("a" for x in (1,2)), x)
>>>print(["a" for x in (1,2)], x)
([‘a’, ‘a’], ‘top’)
([‘a’, ‘a’], 2)
Это бага питона, связанная с тем что локальная переменная x, используемая при создании списка становилась доступной в родительском пространстве имен. Думаю понятно чем грозит данная бага.
Данная бага поправлена в python 3.
http://programmingwats.tumblr.com/page/2
http://nbviewer.ipython.org/github/rasbt/python_reference/blob/master/tutorials/key_differences_between_python_2_and_3.ipynb?create=1
Посмотрим на пример:
>>>x = "top"
>>>print(list("a" for x in (1,2)), x)
>>>print(["a" for x in (1,2)], x)
([‘a’, ‘a’], ‘top’)
([‘a’, ‘a’], 2)
Это бага питона, связанная с тем что локальная переменная x, используемая при создании списка становилась доступной в родительском пространстве имен. Думаю понятно чем грозит данная бага.
Данная бага поправлена в python 3.
Ссылки
https://docs.python.org/3/whatsnew/3.0.html#changed-syntaxhttp://programmingwats.tumblr.com/page/2
http://nbviewer.ipython.org/github/rasbt/python_reference/blob/master/tutorials/key_differences_between_python_2_and_3.ipynb?create=1
Подписаться на:
Сообщения (Atom)