Документация по Python

Библиотека pytest

В: Документация по Python

Введение

Примеры

Настройка py.test

py.test является одним из нескольких библиотек сторонних тестирующих , которые доступны для Python. Он может быть установлен с помощью pip с

 pip install pytest

 

Код для тестирования

Скажем , мы тестируем функцию добавления в projectroot/module/code.py :

 # projectroot/module/code.py
def add(a, b):
    return a + b

 

Код тестирования

Мы создаем тестовый файл в projectroot/tests/test_code.py.Файл должен начинаться с test_ , чтобы быть признанным в качестве файла тестирования.

 # projectroot/tests/test_code.py
from module import code


def test_add():
    assert code.add(1, 2) == 3

 

Запуск теста

Из projectroot мы просто запустить py.test :

 # ensure we have the modules
$ touch tests/__init__.py
$ touch module/__init__.py
$ py.test
================================================== test session starts ===================================================
platform darwin -- Python 2.7.10, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
rootdir: /projectroot, inifile:
collected 1 items

tests/test_code.py .

================================================ 1 passed in 0.01 seconds ================================================ 

Неудачные тесты

Неудачный тест предоставит полезный вывод о том, что пошло не так:

 # projectroot/tests/test_code.py
from module import code


def test_add__failing():
    assert code.add(10, 11) == 33

 

Результаты:

$ py.test
================================================== test session starts ===================================================
platform darwin -- Python 2.7.10, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
rootdir: /projectroot, inifile:
collected 1 items

tests/test_code.py F

======================================================== FAILURES ========================================================
___________________________________________________ test_add__failing ____________________________________________________

    def test_add__failing():
>       assert code.add(10, 11) == 33
E       assert 21 == 33
E        +  where 21 = <function add at 0x105d4d6e0>(10, 11)
E        +    where <function add at 0x105d4d6e0> = code.add

tests/test_code.py:5: AssertionError
================================================ 1 failed in 0.01 seconds ================================================

Введение в тестовые приспособления

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

Наш кодовый файл:

 # projectroot/module/stuff.py
class Stuff(object):
    def prep(self):
        self.foo = 1
        self.bar = 2

 

Наш тестовый файл:

 # projectroot/tests/test_stuff.py
import pytest
from module import stuff


def test_foo_updates():
    my_stuff = stuff.Stuff()
    my_stuff.prep()
    assert 1 == my_stuff.foo
    my_stuff.foo = 30000
    assert my_stuff.foo == 30000


def test_bar_updates():
    my_stuff = stuff.Stuff()
    my_stuff.prep()
    assert 2 == my_stuff.bar
    my_stuff.bar = 42
    assert 42 == my_stuff.bar


 

Это довольно простые примеры, но если наш Stuff объекта нужно намного больше настроек, это будет получить громоздким. Мы видим, что между нашими тестами есть некоторый дублированный код, поэтому давайте сначала соберем его в отдельную функцию.

 # projectroot/tests/test_stuff.py
import pytest
from module import stuff


def get_prepped_stuff():
    my_stuff = stuff.Stuff()
    my_stuff.prep()
    return my_stuff


def test_foo_updates():
    my_stuff = get_prepped_stuff()
    assert 1 == my_stuff.foo
    my_stuff.foo = 30000
    assert my_stuff.foo == 30000


def test_bar_updates():
    my_stuff = get_prepped_stuff()
    assert 2 == my_stuff.bar
    my_stuff.bar = 42
    assert 42 == my_stuff.bar

 

Это выглядит лучше , но у нас еще есть my_stuff = get_prepped_stuff() вызов захламление наши тестовые функции.

py.test светильники на помощь!

Светильники являются гораздо более мощными и гибкими версиями функций настройки теста. Они могут сделать намного больше, чем мы используем здесь, но мы сделаем это по одному шагу за раз.

Сначала мы изменим get_prepped_stuff к арматуре называется prepped_stuff.Вы хотите называть свои приборы именами существительными, а не глаголами, потому что приборы в конечном итоге будут использоваться в самих тестовых функциях. @pytest.fixture указывает , что эта конкретная функция должна быть обработана как приспособление , а не регулярной функции.

 @pytest.fixture
def prepped_stuff():
    my_stuff = stuff.Stuff()
    my_stuff.prep()
    return my_stuff

 

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

 def test_foo_updates(prepped_stuff):
    my_stuff = prepped_stuff
    assert 1 == my_stuff.foo
    my_stuff.foo = 30000
    assert my_stuff.foo == 30000


def test_bar_updates(prepped_stuff):
    my_stuff = prepped_stuff
    assert 2 == my_stuff.bar
    my_stuff.bar = 42
    assert 42 == my_stuff.bar

 

Теперь вы можете понять, почему мы назвали его существительным. но my_stuff = prepped_stuff линия довольно много бесполезной, так что давайте просто использовать prepped_stuff непосредственно вместо этого.

 def test_foo_updates(prepped_stuff):
    assert 1 == prepped_stuff.foo
    prepped_stuff.foo = 30000
    assert prepped_stuff.foo == 30000


def test_bar_updates(prepped_stuff):
    assert 2 == prepped_stuff.bar
    prepped_stuff.bar = 42
    assert 42 == prepped_stuff.bar

 

Теперь мы используем светильники! Мы можем пойти дальше, изменив область действия прибора (чтобы он запускался только один раз для каждого тестового модуля или сеанса выполнения набора тестов, а не один раз для каждой тестовой функции), создавая приборы, использующие другие приборы, параметризовав прибор (так, чтобы прибор и все тесты с использованием этого прибора выполняются несколько раз, по одному разу для каждого параметра, переданного устройству), приборы, которые считывают значения из вызывающего их модуля ... как упоминалось ранее, приборы имеют гораздо большую мощность и гибкость, чем обычная функция настройки.

Очистка после испытаний.

Допустим, наш код вырос и наш объект Stuff теперь нуждается в специальной очистке.

 # projectroot/module/stuff.py
class Stuff(object):
def prep(self):
    self.foo = 1
    self.bar = 2

def finish(self):
    self.foo = 0
    self.bar = 0

 

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

 @pytest.fixture
def prepped_stuff(request):  # we need to pass in the request to use finalizers
    my_stuff = stuff.Stuff()
    my_stuff.prep()
    def fin():  # finalizer function
        # do all the cleanup here
        my_stuff.finish()
    request.addfinalizer(fin)  # register fin() as a finalizer
    # you can do more setup here if you really want to
    return my_stuff

 

Использование функции финализатора внутри функции может быть довольно сложно понять на первый взгляд, особенно если у вас есть более сложные приборы. Вместо этого вы можете использовать выход приспособление , чтобы сделать то же самое с более читаемом потоком выполнения. Единственное отличие в том , что вместо того , чтобы использовать return мы используем yield на части прибора , где установка делаются и контроль должен идти к тестовой функции, затем добавьте весь код очистки после yield.Мы также украсить его как yield_fixture так , что py.test знает , как справиться с этим.

 @pytest.yield_fixture
def prepped_stuff():  # it doesn't need request now!
    # do setup
    my_stuff = stuff.Stuff()
    my_stuff.prep()
    # setup is done, pass control to the test functions
    yield my_stuff
    # do cleanup 
    my_stuff.finish()

 

И это завершает вступление к тестовым приспособлениям!

Для получения дополнительной информации см официальной py.test арматуры документация и документация арматуре официального выхода

Синтаксис

Параметры

Примечания

Еще от кодкамп
Замечательно! Вы успешно подписались.
Добро пожаловать обратно! Вы успешно вошли
Вы успешно подписались на кодкамп.
Срок действия вашей ссылки истек.
Ура! Проверьте свою электронную почту на наличие волшебной ссылки для входа.
Успех! Ваша платежная информация обновлена.
Ваша платежная информация не была обновлена.