Pytest эффективно тестирует код Python
Pytest эффективно тестирует код Python

в этой статье,Генерал Юн Дуои Давайте учиться вместеPythonЛучшее визтестмодуль--Pytest,Основное обучение заключается в следующем:

  • Pytestизпреимущество
  • Как гарантироватьтестлицо без гражданства
  • Как сделать так, чтобы это повторялосьтест ДажеЛегко понять
  • Как назвать или настроить группуГруппатест
  • Как создатьиподдерживатьМногоразовыйизтест程序
  • 怎么использоватьpytestДелатьданныенаукаизединицатест

Обзор Pytest

Рекомендуется реализовать вручную.в этой статьеизнесколько примеров,чтобы углубить впечатление。Сначала вам нужно установитьpytest。с большинствомPythonТот же пакет программного обеспечения,мы можемиспользовать pip от PyPI из Установить вpytest

Язык кода:javascript
копировать
$ python -m pip install pytest

PytestКоманда теперь будет у насиз Доступен в среде установки。

pytest — это очень зрелая полнофункциональная среда тестирования Python. Ее основные функции заключаются в следующем:

  • 1. Простой и гибкий, удобный в использовании и богатый документацией;
  • 2. Параметр поддержки, который позволяет детально контролировать варианты использования;
  • 3、Он может поддерживать простые и сложные модули и сложные функции, а также может использоваться для автоматизации selenium/appnium и других задач автоматизации.、Тест автоматизации интерфейса (pytest+requests);
  • 4. В pytest имеется множество сторонних инструментов.,И может быть настроен и расширен,относительно прост в использованииизнравитьсяpytest-selenium(интегрированныйselenium)、pytest-html (генерация идеального отчета htmltest)、pytest-rerunfailures (повторное выполнение неудачных случаев)、pytest-xdist (многопроцессорный дистрибутив) и т. д.;
  • 5. тестовый вариант использования обработки isskipиxfail;
  • 6. Хорошо сочетается с инструментами CI.,Например, Дженкинс

Что такое Пайтест

Если вы когда-либо писали модульные тесты, вам следовало использовать Python серединаизunittestмодуль,У нашего сегодняшнего главного героя, Pytest, есть изображение точки.

В настоящее время в решении находится код наиболее популярных фреймворков тестирования. unittest некоторые вопросы, они pytest Это экология, плагин и Python сам по себе. тестовая система.

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

большинствотествсе следуютОрганизация-Действие-Утверждение(Arrange-Act-Assert)измодель。

  1. договариватьсяили установитьтестизсостояние
  2. проходитьнастраиватьиспользоватьнекоторыйфункцияилиметод Приходитьпринять меры
  3. утверждениенекоторое конечное условие истинно

Структура тестирования обычно связана с нашим тестированием.,Предоставить информацию в случае неудачи утверждения. Например,unittest Множество полезных инструментов утверждения предоставляются «из коробки». Однако даже небольшой набор тестов требует значительного объема стандартного кода.

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

Язык кода:javascript
копировать
# test_with_unittest.py
from unittest import TestCase
class TryTesting(TestCase):
    def test_always_passes(self):
        self.assertTrue(True)

    def test_always_fails(self):
        self.assertTrue(False)

Тогда ты сможешьиспользоватьunittestизdiscoverПараметрыоткомандная строкасерединазапустить этитест。

Язык кода:javascript
копировать
$ python -m unittest discover
F.
============================================================
FAIL: test_always_fails (test_with_unittest.TryTesting)
------------------------------------------------------------
Traceback (most recent call last):
  File "/.../test_with_unittest.py", line 9, in test_always_fails
    self.assertTrue(False)
AssertionError: False is not True

------------------------------------------------------------
Ran 2 tests in 0.001s

FAILED (failures=1)

тест пройден,одинтестнеудача。Хотя мы доказалиunittestдействителениз,Но дальше нам понадобится:

  1. отunittestимпортироватьTestCaseдобрый
  2. создаватьTestCaseиз ПодклассTryTesting
  3. существоватьTryTestingсерединадлякаждыйтест Писатьодинметод
  4. использовать unittest.TestCase серединаиз self.assert* в рамках методаутверждение。

Хотя объем этого кода довольно велик,но потому что этолюбой тестнеобходимыйизминимумизкод,В конечном итоге мы все равно неоднократно пишем что-то вродеизкод。мы можемпроходить pytestпрямойиспользоватьPythonизassertКлючевые слова для упрощения этого рабочего процесса。

Язык кода:javascript
копировать
# test_with_pytest.py
def test_always_passes():
    assert True
def test_always_fails():
    assert False

Нам не нужно использовать какой-либо импорт или классы, потому что мы можем использовать assert Ключевые слова, которые нам тоже не нужно учить или запоминать unittest все разные в self.assert* метод. Если бы вы могли написать выражение, которое ожидало бы, что его значение будет "True",Такpytestпоможет намтестэто。

Язык кода:javascript
копировать
$ pytest
================== test session starts =============================
platform linux -- Python 3.7.3, pytest-5.3.0, py-1.8.0, pluggy-0.13.0
rootdir: /.../effective-python-testing-with-pytest
plugins: randomly-1.0.0, mock-1.2, cov-2.0.0
collected 2 items

test_with_pytest.py .F                                          [100%]

======================== FAILURES ==================================
___________________ test_always_fails ______________________________

    def test_always_fails():
>       assert False
E       assert False

test_with_pytest.py:5: AssertionError
============== 1 failed, 1 passed in 0.07s =========================

Pytestпоказыватьизтест Результат тот же, что иunittestдругой,Отчет представлен ниже.

  1. Статус системы,В том числе мы установилиизPython、pytestилюбой другойплагиниз Версия
  2. rootdir,Или выполните поиск в каталоге Конфигурация.
  3. поиск、Найдено количество изтестов

Вывод аналогиченunittestизпосле синтаксисаизрезультаттестсостояние:

  • точка.выражатьтестпроходить。
  • Fвыражать Стестнеудача。
  • Eвыражать Должентест Произошло исключение。

На провализтест,Сообщить о сбое Дават подробнее。существоватьвышеизпримерсередина,тестнеудачада因дляassert FalseВсегданеудача。

Вот еще несколько примеров краткости утверждений.

Язык кода:javascript
копировать
def test_uppercase():
    assert "loud noises".upper() == "LOUD NOISES"

def test_reversed():
    assert list(reversed([1, 2, 3, 4])) == [4, 3, 2, 1]

def test_some_primes():
    assert 37 in {
        num
        for num in range(1, 50)
        if num != 1 and not any([num % div == 0 for div in range(2, num)])
    }

Pytestизкоэффициент кривой обученияunittestБыть поверхностным,Потому что нам не нужно изучать новоеизструктура。вернобольшинство人Приходить说assertтест Дажелегко понять。

Управление состоянием и зависимостями

Наши тесты часто опираются на фрагменты данных некоторых объектов кода. существовать unittest , мы можем извлечь эти зависимости в setUp() и tearDown() методсередина,Таким образом, каждый тест в классе сможет их использовать. но сделай это,может быть непреднамереннымсерединаделатьтестконкретномуданныеили объектизполностью зависим от“Скрытый”。

Со временем неявные зависимости могут привести к сложному беспорядку в коде, который нам придется разбирать, чтобы понять наши тесты. Тесты должны помочь нам сделать наш код более понятным. Если сам тест труден для понимания, то у нас могут быть проблемы!

Pytestвзятыйдругойизметод。этогиднасруководитьявныйЗаявление о зависимости,потому чтоfixture[1]из Доступность,Эти Заявление о зависимостивсе еще Может Тяжелыйиспользовать。**pytest fixtureдлятест Создание комплектаданныеилитест Двойная копияилиисходныйизменятьнекоторый Статус системыизфункция. Любой, кто хочет использоватьfixtureТесты это вседолженявныйприниматьэтокакпараметр**,Поэтому зависимости всегда объявляются заранее.

FixtureДостаточно хорошоиспользоватьдругойfixture,Объявите их также как зависимости. То есть со временем,fixtureможет стать громоздкимимодульизменять。Хотя это будетfixtureвставлятьприезжатьдругойfixtureиз Способность обеспечивает огромныеизгибкость,Но по мере роста набора тестов,Это также усложняет управление зависимостями.

Тестовая фильтрация

По мере роста набора тестов мы можем обнаружить, что хотим запустить только несколько тестов для какой-либо функции. pytestпредоставил Некоторыйметод。

  • фильтровать по имени。может бытьpytestОграничить запуски только полными именами, соответствующими определенному выражению.изтест。Можетиспользовать -k параметр для завершения этой операции
  • Область каталога。По умолчанию,pytestбудет запускать только тесуществоватькогдав предыдущем каталогеизтест。
  • Классификационный тестpytestМожет Сумкавключатьилиисключатьнас Конечноправедныйизконкретные категорииизтест。мы можемиспользовать-mпараметрчтобы добиться этоготочка。

PytestМожетдлятестсоздаватьотметка,или пользовательские этикетки. Тест может иметь несколько тегов,Их можно использовать для детального контроля над тем, какой тест выполняется.

Параметризация теста

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

UnittestПредоставляет возможность объединить несколькотестсобран водинизметод,Но в отчете о результатах он не отображается как отдельный изтест. Если тест не пройден,Все остальные прошли,Таквсеиндивидуальныйтест组все ещевстреча返回одиннеудачаизрезультат。Pytestобеспечил себяизрешение,Каждый тест может пройти или не пройти независимо.

подключаемый модуль

Pytestлучшийизэкология этоэтоверно Конечносистемаи Шиничиточкаиз Функция обогащения,Почти любую программу можно взломать и модифицировать. поэтому,pytestизиспользовать Домохозяйство развито.один Богатыйизоно работаетплагинизэкосистема。

Хотя некоторыеpytestплагинсосредоточиться на конкретныхизрамка,нравитьсяDjango[2],Но другой разъем работает с большинством тестовых наборов.

Исправления: управление состоянием и зависимостями.

Pytest fixtures Это способ предоставить данные, тестовые двойники или настройки состояния для тестов.Fixturesда Может Вернуть несколько чиселценитьизфункция。каждый зависит отfixtureизтестдолжен明правильныйпринимать Долженfixtureкакпараметр。

Когда создавать светильники

написать функцию format_data_for_display(),Используется для обработки возврата конечных точек API. Эти данные представляют собой список людей из,У каждого есть имя, фамилия и должность. Функция должна вывести список строк из,Сюда входят полное имя каждого человека, двоеточие и титул. Следующий код.

Язык кода:javascript
копировать
def format_data_for_display(people):
    ...  # Implement this!

def test_format_data_for_display():
    people = [
        {
            "given_name": «Юнь Дуоцзюнь»,
            "family_name": "Python",
            "title": «Старший инженер-алгоритмист»,
        },
        {
            "given_name": «маленькая обезьянка»,
            "family_name": "Python",
            "title": "Руководитель проекта",
        },
    ]

    assert format_data_for_display(people) == [
        «Юнь Дуоцзюнь Python: Старший инженер-алгоритмист",
        "маленькая обезьянка Python: Руководитель проекта",
    ]

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

Язык кода:javascript
копировать
def format_data_for_excel(people):
    ... # Implement this!

def test_format_data_for_excel():
    people = [
        {
            "given_name": «Юнь Дуоцзюнь»,
            "family_name": "Python",
            "title": «Старший инженер-алгоритмист»,
        },
        {
            "given_name": «маленькая обезьянка»,
            "family_name": "Python",
            "title": "Руководитель проекта",
        },
    ]

    assert format_data_for_excel(people) == """
                                given,family,title
                                Юн Дуоцзюнь, Python, старший инженер-алгоритм
                                маленькая обезьянка, Python, менеджер проекта
                                """

Что, если мы обнаружим, что пишем несколько тестов, используя одни и те же базовые тестовые файлы?,Так Можетиспользоватьодинfixture,Собрать повторяющиеся изданные в одну функцию,использовать@pytest.fixtureПриходитьвыражать Долженфункциядаодинpytestизfixture

Язык кода:javascript
копировать
import pytest

@pytest.fixture
def example_people_data():
    return [
        {
            "given_name": «Юнь Дуоцзюнь»,
            "family_name": "Python",
            "title": «Старший инженер-алгоритмист»,
        },
        {
            "given_name": «маленькая обезьянка»,
            "family_name": "Python",
            "title": "Руководитель проекта",
        },
    ]

Вы можете прочитать это как параметрдобавить вприезжатьтестсередина Приходитьиспользовать Долженfixture。этоизценить Воляда Долженfixtureфункцияизвозвращаемое значение。

Язык кода:javascript
копировать
def test_format_data_for_display(example_people_data):
    assert format_data_for_display(example_people_data) == [
        «Юнь Дуоцзюнь Python: Старший инженер-алгоритмист",
        "маленькая обезьянка Python: Руководитель проекта",
    ]

def test_format_data_for_excel(example_people_data):
    assert format_data_for_excel(example_people_data) == """
                                given,family,title
                                Юн Дуоцзюнь, Python, старший инженер-алгоритм
                                маленькая обезьянка, Python, менеджер проекта
                                """

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

Когда использовать приспособления

Fixtureподходящийиспользовать Ю Чусинсуществоватьмногоиндивидуальныйтестсерединаиспользоватьизтакой жеизданныеили объект,Но он не подойдет тем, кому нужно внести небольшие изменения в данные тестизтеста. Потому что это добавляет уровень косвенности,существоватьтестнаборсерединаприсоединитьсяfixtureЧаще, чем присоединениеданныеили объектвозможный Даже Плохой。

когданайди себясуществоватьвсеиндивидуальныйпроектсерединанеоднократноиспользоватькто-тоfixtureчас,мы можем Воляfixtureоттестмодульдвигатьсяприезжать Даже ПроходитьиспользоватьизfixtureСвязанныймодульсередина。так Сразуможет бытьэтоихимпортироватьприезжатьлюбойнуждатьсяэтоихизтестмодульсередина。

Pytest существоватьвсеиндивидуальный Оглавлениеструктурасередина Находитьconftest.py модуль。каждыйconftest.pyдля pytest Найти его можно в дереве файлов Конфигурация. Может находиться во всем файле и в родительском каталоге и в любом подкаталоге и спользовать в определенном conftest.py середина Конечноправедныйизлюбойfixture。этотдаодиннаиболее широко распространенныйиспользоватьизfixtureизхорошее место。

Параметры светильника

Pytestсередина Можетиспользовать@pytest.fixture装饰器Приходить装饰одинметод,Украшенный метод из имени метода может быть передан в тестовый метод в качестве параметра. Операцию инициализации перед тестированием можно завершить таким образом.,Также возможно вернуть функцию данных Даваттест.

Язык кода:javascript
копировать
import pytest
class TestFixture:
    @pytest.fixture(scope='function')
    def example_people_data():
        return [
            {
                "given_name": «Юнь Дуоцзюнь»,
                "family_name": "Python",
                "title": «Старший инженер-алгоритмист»,
            },
            {
                "given_name": «маленькая обезьянка»,
                "family_name": "Python",
                "title": "Руководитель проекта",
            },
        ]

    def test_format_data_for_display(example_people_data):
        assert format_data_for_display(example_people_data) == [
            «Юнь Дуоцзюнь Python: Старший инженер-алгоритмист",
            "маленькая обезьянка Python: Руководитель проекта",
        ]
Параметр объема прибора

Разделить по размеру сферы действия,Они есть:session>module>class>function

Язык кода:javascript
копировать
@pytest.fixture(scope='function') # область действия Значение по умолчанию — функция
  • functionфункцияилиметодуровень Всевстречаодеялонастраиватьиспользовать
  • classдобрыйуровеньнастраиватьиспользоватьодин раз
  • moduleмодульуровеньнастраиватьиспользоватьодин раз
  • sessionдамногоиндивидуальныйдокументнастраиватьиспользоватьодин раз,Можетчерез.pyдокументнастраиватьиспользовать,каждый.pyФайлmodule

Вы можете проверить область видимости с помощью следующего скрипта:

Изменяя область видимости из значения перечисления,Вы можете увидеть эффект,Можетсмотретьприезжатьprint('Вызов метода fillna')существоватьдругойизscopeПараметры Вниз,Количество распечаток разное.

Язык кода:javascript
копировать
import pytest

@pytest.fixture(scope='function')
def example_people_data():
    return [
        {
            "given_name": «Юнь Дуоцзюнь»,
            "family_name": "Python",
            "title": «Старший инженер-алгоритмист»,
        },
        {
            "given_name": «маленькая обезьянка»,
            "family_name": "Python",
            "title": "Руководитель проекта",
        },
    ]

class TestFixture:
    def test_format_data_for_display(example_people_data):
        assert format_data_for_display(example_people_data) == [
          «Юнь Дуоцзюнь Python: Старший инженер-алгоритмист",
          "маленькая обезьянка Python: Руководитель проекта",
        ]
Параметры автоматического использования прибора

Если вы хотите, чтобы каждый тестовый вариант использования был добавлен вfixtureФункция,Так Можетиспользовать@pytest.fixtureвизautouseпараметр,autouse='true'则встреча自动应использоватьприезжать Местооно работаетпримерсередина。

конфигурация conftest.py

вышеодин案примердасуществоватьтакой жеодин.pyдокументсередина,многоиндивидуальныйиспользоватьпримернастраиватьиспользоватьодинданные Образецexample_people_data,Если существует несколько файлов .pyiz, вам нужно вызвать этот dataiz,Тогда вы не сможете записать данные в вариант использования.

На этом этапе должен быть файл конфигурации.,Отдельное управление некоторыми предустановленными сценариями работы.,pytestв Чтение по умолчаниюconftest.pyвиз Конфигурация

conftest.pyодеялоpytest视дляодинместныйплагин Библиотека,в целомиспользовать Вscope='session'уровеньизfixture

использоватьconftest.pyизправило:

  1. conftest.pyЭто имя файла фиксированоиз,нельзя изменить
  2. conftest.pyи бежатьиспользоватьпримерсуществоватьтакой жеодин Сумка Вниз,и Должен Сумкасередина Должно быть__init__.pyдокумент
  3. использоватьизчасждатьненужныйимпортироватьconftest.py,pytest автоматически загрузится,В какой пакет мне его положить?,Это действительно в рамках этого пакета.

Fixtureиз Другойодиниспользовать途даЗащитите доступ к ресурсам。Предположим, мы обработалиAPIнастраиватьиспользоватьизкод编Писать Понятноодинтестнабор,и хотите убедиться, что набор тестов не выполняет никаких реальных сетевых вызовов,Несмотря на тотест Случайно выполнил настоящийиз网络настраиватьиспользоватькод。Pytest предоставилодинmonkeypatch[3] изfixtureзаменить значениеи Поведение,Вы можете использовать его для достижения отличных результатов:

Язык кода:javascript
копировать
# conftest.py
import pytest
import requests

@pytest.fixture(autouse=True)
def disable_network_calls(monkeypatch):
    def stunted_get():
        raise RuntimeError("Network access not allowed during testing!")
    monkeypatch.setattr(
        requests, 
        "get",
        lambda *args,
        **kwargs: stunted_get())

в conftest.py помещен в disable_network_calls() и добавить autouse=True вариант, мы можем гарантировать, что сетевые вызовы будут отключены в каждом тесте для всего пакета. любой вызов выполнения requests.get() Тесты кода запустят RuntimeError, указывающий на неожиданный сетевой вызов.

Оценки: классификационный тест

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

PytestМожетдлятест Определить категории,И укажите опцию включения или исключения категорий при запуске пакета. Мы можем использовать любое число категорий, чтобы отметить тест.

Маркировка тестов полезна для категоризации тестов по подсистемам или зависимостям. Например, если для некоторых тестов требуется доступ к базе данных, вы можете создать @pytest.mark.Database_access отметка.

намекать:因длямы можем Даватьнасизотметкаростлюбойимя,Поэтому легко набрать или неправильно запомнить имя отметкаиз,pytest Для тегов, которые он не распознает, будет выдано предупреждение. Даватьpytestкоманда плюс--strict-markersПараметры МожетубеждатьсясуществоватьpytestКонфигурациясерединазарегистрироватьсятестсерединаизвсеотметка Все。если бы тольконасиметьлюбой未зарегистрироватьсяизотметка,Все это помешает нам запустить тест.

Если вы хотите запускать только те, которым требуется доступ к библиотеке данных, изтестируйте,Такмы можемиспользоватьpytest -m database_access бежатьвсеизтест。мы можемиспользоватьpytest -m "not database_access"Запустить, кроме необходимыхданные Библиотекадоступизтест。насдаже Можетиспользоватьautouse fixtureограничиватьданные Библиотекаиздоступ,Только для тех, кто отмечен знакомdatabase_accessизтест。

Некоторыйплагинпроходить Защитите доступ к ресурсамрасширятьотметкаиз Функция。pytest-django[4]плагинпредоставилодинdjango_dbотметка.любой没иметьэтотиндивидуальныйотметкаизтестсуществоватьпытатьсядоступданные Библиотекачас Всевстречанеудача。Нет.одинпытатьсядоступданные БиблиотекаизтествызоветDjangoтестданные Библиотекаизсоздавать。

добавить в django_db Требование тегирования вынуждает вас явно объявлять зависимости, т. е. вы можете запускать независимые от базы данных тесты быстрее, потому что pytest -m "not django_db" Не позволит тесту инициировать создание базы данных. Это экономит много времени.

pytestпредоставил Некоторый Прямо из коробкииспользоватьизотметка.

  • skip:Пропустить безоговорочнотест
  • skipif:Если выражение имеет значение true, пропустите его.тест
  • xfail:Конечнотестнеудача,Если решение не удалось,Результаты всего тура теста все равно пройдут
  • parametrize(Уведомлениезаклинание):создаватьмногоиндивидуальныйдругойценитьизтесткогдапараметр

Можетпроходитьбегатьpytest --markersПосмотреть полностьюизpytestотметкасписок。

Параметризация: комбинаторное тестирование

Ранее в этой статье,нассмотретьприезжать Понятнонравитьсячтоиспользоватьpytest fixtrue проходить Извлечение общих зависимостей(fixtureсодержание)уменьшитькодповторить。такой жечас Также упомянитеприезжать Понятноодинfixtrue不подходящийиспользоватьиз Состояние:когдаиметь输入и输出略иметьдругойизтестчас,Сразу不Таконо работает Понятно。этотчас Может**parametrize**[5]одинокийтест Конечноправедный,иpytestвстреча根据指Конечноизпараметрсоздаватьтестиз Варианты。

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

Язык кода:javascript
копировать
def test_is_palindrome_empty_string():
    assert is_palindrome("")

def test_is_palindrome_single_character():
    assert is_palindrome("a")

def test_is_palindrome_mixed_casing():
    assert is_palindrome("Bob")

def test_is_palindrome_with_spaces():
    assert is_palindrome("Never odd or even")

def test_is_palindrome_with_punctuation():
    assert is_palindrome("Do geese see God?")

def test_is_palindrome_not_palindrome():
    assert not is_palindrome("abc")

def test_is_palindrome_not_quite():
    assert not is_palindrome("abab")

За исключением двух последних тестов, все остальные тесты имеют одинаковую структуру.

Язык кода:javascript
копировать
def test_is_palindrome_<in some situation>():
    assert is_palindrome("<some string>")

Можетиспользовать@pytest.mark.parametrize()существоватьэтотиндивидуальныйструктурасерединазаполнятьдругойизценить,Значительно сокращен тесткод.

Язык кода:javascript
копировать
@pytest.mark.parametrize("palindrome", [
    "",
    "a",
    "Bob",
    "Never odd or even",
    "Do geese see God?",
])
def test_is_palindrome(palindrome):
    assert is_palindrome(palindrome)

@pytest.mark.parametrize("non_palindrome", [
    "abc",
    "abab",
])
def test_is_palindrome_not_palindrome(non_palindrome):
    assert not is_palindrome(non_palindrome)

parametrize()из Нет.одинпараметрдаодинразделенные запятымиизпараметрстрока имени。второйпараметрдаодинпредставлятьпараметрценитьиз Предокилиодинокийценитьизсписок。Можетдальшепараметризменять,Объедините все тесты в один тест.

Язык кода:javascript
копировать
@pytest.mark.parametrize("maybe_palindrome, expected_result", [
    ("", True),
    ("a", True),
    ("Bob", True),
    ("Never odd or even", True),
    ("Do geese see God?", True),
    ("abc", False),
    ("abab", False),
])
def test_is_palindrome(maybe_palindrome, expected_result):
    assert is_palindrome(maybe_palindrome) == expected_result

Это не только сокращает код,И использовать параметризацию отделяет поведение тестовыхоттестов.,Таким образом, вы можете четко знать, что делает тест!

Отчеты о длительности: борьба с медленным тестированием

Каждый раз при реализации кода переключается на среду тестового кодирования.,Будут некоторые накладные расходы,И очень медленно.

Как уже говорилось ранее, при беге тестиз,Вы можете идентифицировать и отфильтровать тест. Если вы хотите увеличить скорость теста,Так Сразу很иметь必要知道哪些тест Может Обеспечить максимумизулучшать。PytestМожет Автоматическая записьтестчасмежду,и сообщить о самом медленномизtop nиндивидуальныйтест。

Давать pytest команда плюс --durations Параметры Пучокпродолжительностьотчет плюсприезжатьтестрезультатвнутри。--durationsприниматьодинвсе数добрый型n,И сообщит о самом медленном времени тестирования. Содержание отчета соответствует результатам теста.

Язык кода:javascript
копировать
$ pytest --durations=3
3.03s call     test_code.py::test_request_read_timeout
1.07s call     test_code.py::test_request_connection_timeout
0.57s call     test_code.py::test_database_read
======================== 7 passed in 10.06s ==============================

Каждый тест, отображаемый в отчете о продолжительности, является ускоренным проектом, поскольку он занял больше времени, чем общее среднее значение.

Уведомление,Некоторые тесты могут иметь невидимые затраты на настройку. Мы упоминали ранее,Нет.один标иметьdjango_dbизтествызоветDjangoтестданные Библиотекаизсоздавать。продолжительность Отчет отражает триггерданные Библиотекасоздаватьизтестсерединанастраиватьданные Библиотекаизчасмежду,Это может ввести в заблуждение.

Практичные плагины

Ранее в этой статье,已经Понятно解Понятно Некоторыйиметь价ценитьизpytestплагин,Мы можем изучить эти и некоторые другие плагины более подробно ниже.

pytest-randomly

pytest-randomly[6]Делать Понятно一件смотреть似简单但很иметь价ценитьизиметь значение:это迫делатьтестслучайным образомиз Запускать последовательно。

Таким образом, вы можете обнаружить те, которые зависят от запуска изтеста в определенном порядке.,этот意味СэтоихвернодругойтестиметьодинЗависимости с состоянием。нас不太возможныйсуществоватьpytestсерединаот Начни строить с нулятестнабор,это Дажеиметьвозможный发生существоватьнасмигрироватьприезжатьpytestизтестнаборсередина。

Плагин напечатает начальное значение в описании конфигурации, которое можно использовать для запуска тестов в том же порядке при попытке устранить проблему.

pytest-cov

Если измерить степень покрытия тестом достижения кодиз,насвозможныйвстречаиспользоватьcoverage[7]Сумка。pytest-cov[8]интегрированный Понятноcoverage,Месток Можетбегатьpytest --covПриходите и посмотритетестотчет о покрытии。

pytest-django

pytest-django[9]для обработкиDjangoтестпредоставил Некоторыйоно работаетизfixtures и marks。нас Ранее в этой статьесмотретьприезжать Понятноdjango_dbотметка,иrf fixtureпредусмотреноDjangoизRequestFactory[10]Примеризпрямойдоступ。settings fixtureпредоставилодинбыстрыйнастраиватьиликрышкаDjangoнастраиватьизметод。эта параDjangoтест效率даодиночень большойизпродвигать!

pytest-bdd

pytestМожетиспользовать Приходитьбегать传统единицатестза пределами диапазонаизтест。Поведение Стимулируйте развитие(BDD)Поощрять писать можноизиспользоватьсемья Поведениеиожидатьиз Описание на чистом языке,Тогда ты сможешьиспользоватьэто Приходить决Конечнода否выполнитьодинособенный Конечноиз Функция。pytest-bdd[11]помощьнасиспользоватьGherkin[12]длянасизкод编Писать Функциятест。

мы можемпроходитьэтотиндивидуальныйширокоизСписок сторонних плагинов[13]查смотреть哪些другойплагин Можетиспользовать Вpytest

Научный тест по блоку данных

данные Наука и промышленность,особенно ускорение,Обычная ошибка — это результат отсутствия написания модульного теста. По крайней мере, вы можете проверить, нормальный ли ввод.,Фактически, большинство научных проектов данных представляют собой отданные процессы обработки.

Проекты разные, но выполнение некоторых общих тестов тоже отличается.

Отсутствующие значения
Язык кода:javascript
копировать
#catch missing values assert 
df['column'].isna().sum()<1 
Повторяющиеся значения
Язык кода:javascript
копировать
# check there is no duplicate 
assert len(df['id'].unique())==df.shape[0]
assert df.groupby(['date','id']).size().max()==1
форма данных
Язык кода:javascript
копировать
# have data for all ids? 
assert df['id'].unique().shape[0] == len(ids)

# function returns have shapes as expected 
assert all([some_funtion(df).shape == df[0].shape for df in dfs])
Диапазон значений
Язык кода:javascript
копировать
assert df.groupby('date')['percentage'].sum()==1 
assert all (df['percentage']<=1)
assert df.groupby('name')['budget'].max()<=1000
Качество соединения

d6tjoin[14]Можетисследовать Качество соединения。

Язык кода:javascript
копировать
assert d6tjoin.Prejoin([df1,df2],['date','id']).is_all_matched()
Функция обработки
Язык кода:javascript
копировать
assert preprocess_function("name\t10019\n")==["name",10019]
assert preprocess_missing_name("10019\n") is None
assert preprocess_text("Do you Realize those are genetically modified food?" ) == ["you","realize","gene","modify","food"]

Практическое введение в использование

Напишите правила

Написать примеры тестов pytest очень просто, достаточно следовать следующим правилам:

  • тестовый файл начинается с test_ (или заканчивается на _test) pytestвстреча找когда前к及递归Находить子документ夹Вниз面всеизtest_.py или_test.pyиздокумент,Считайте его тестовым файлом (если явный не указывает путь к файлу)
  • Имя класса testИмя класса начинается с Test и не может иметь метод init. Если имя класса начинается с Test и класс класса содержит метод init, будет выдано предупреждение, намекать PytestCollectionWarning: cannot collect test class 'TestXXX'
  • тестовая функция начинается с test_
  • утверждениеиспользоватьбазовыйизassertВот и все
Язык кода:javascript
копировать
# -*- coding:utf-8 -*-
# pytest1.py
import pytest

@pytest.fixture(scope='function')
def setup_function(request):
    def teardown_function():
        print("teardown_function called.")
    request.addfinalizer(teardown_function)  # Эта встроенная функция выполняет работу по демонтажу
    print('setup_function called.')

@pytest.fixture(scope='module')
def setup_module(request):
    def teardown_module():
        print("teardown_module called.")
    request.addfinalizer(teardown_module)
    print('setup_module called.')

@pytest.mark.website
def test_1(setup_function):
    print('Test_1 called.')

def test_2(setup_module):
    print('Test_2 called.')

def test_3(setup_module):
    print('Test_3 called.')
    assert 2==1+1              # Подтвердите, соответствуют ли результаты теста ожидаемым, с помощью утверждения утверждения.
Операции по установке и демонтажу

этотвнутри补充одинsetupиteardownЗнания, связанные с эксплуатацией。

Следующая статьясерединаunittestвиспользоватьпрефикси Заднийsetupиteardownочень хорошийиспользовать,Выполняйте его перед началом каждого варианта использования и после его завершения.

  • setup,Выполнить перед тестовой функцией или классом,Полная подготовка,Например, ссылка на библиотеку данных, тестированные, открытый файл и т. д.
  • teardown,Выполнить после тестовой функции или класса,Полные отделочные работы,Например, отключение ссылки на библиотеку данных, переработку ресурсов памяти и т. д.
  • Примечание:также МожетвfixtureфункциясерединапроходитьyieldвыполнитьsetupиteardownФункция

когда然还иметь Даже СтаршийточкаизsetupClassиteardownClass,Нужно сотрудничать@classmethodДекораторы вместеиспользовать,При автоматизации селена из,Его эффективность особенно выдающаяся,Вы можете запустить браузер один раз, чтобы выполнить несколько вариантов использования.

Pytestрамкатакжеиметьдобрый似Вsetupиteardownизграмматика,И есть больше, чем просто эти четыре

уровень выполнения сценария использования
  • Уровень модуля (setup_module/teardown_module) начинается в начале и в конце модуля.,Глобальный из
  • Уровень функции (setup_function/teardown_function) действует только для случаев использования функции (не в классах).
  • Уровень класса (setup_class/teardown_class) запускается только один раз до и после класса (в классе).
  • Уровень метода (setup_method/teardown_method) начинается в начале и в конце метода (в классе).
  • Внутри класса (setup/teardown) выполняется до и после вызова метода
Преимущества светильника

FirtureотносительноsetupиteardownПриходить说应Должениметьк Вниз几точка Преимущества

  • Гибкое именование,не ограничиваетсяsetupиteardownэтот几индивидуальныйжизньимя
  • conftest.py Конфигурациявнутри Можетвыполнитьданныеобщий,ненужныйimportСразу能自动找приезжать Некоторый Конфигурация
  • scope="module" Можетвыполнитьмногоиндивидуальный.pyчерездокументобщийпрефикс, Каждыйодин.pyдокументнастраиватьиспользоватьодин раз
  • scope="session" квыполнитьмногоиндивидуальный.pyчерездокументиспользоватьодинsessionПриходить完成многоиндивидуальныйиспользоватьпример

Рабочие параметры

У вас могут возникнуть такие вопросы,Сейчас все используют такие инструменты, как PycharmизIDE.,Зачем вам нужно научиться запускать изпараметры в командной строке?

Pytestрамкадаодинтестрамка,Если вам нужно интегрировать его в Дженкинс,,Вам нужно использовать командную строку для его выполнения,Иногда вам нужно выполнить несколько вариантов использования,Удобнее использовать файлы командной строки.

PytestМожетсуществоватькомандная строка执行,При выполнении из в командной строке,Вы можете привести много параметров,Вниз面介绍几种常использоватьприезжатьизпараметриспользовать Закон:(использоватьpytest --helpМожетсмотретьприезжатьжизнь令параметриз Справочная документация)

  • Выполнить без параметра

Использование: pytest или py.test прочитает все файлы, классы, методы и функции, которые соответствуют правилам в текущем пути, и выполнит их.

  • -vпараметр

Распечатайте подробную информацию журнала работы, чтобы облегчить обнаружение проблемы.

  • -sпараметр

Результаты можно вывести на консоль. Если в коде для вывода информации используется оператор печати, без этого параметра консоль не будет отображать содержимое печати.

  • -kпараметр

Используйте этот параметр, чтобы указать вариант использования, соответствующий требованиям для запуска. Использование следующее:

Язык кода:javascript
копировать
pytest -k "имя класса"
pytest -k "имя метода"
pytest -k «Имя класса and not имя метода"

Уведомление: -kпараметрс последующимиз Кавычки могут быть толькоиспользоватьдвойные кавычки"",не могуиспользоватьодинарная кавычка'',В противном случае вариант использования не будет распознан.,При запуске будет сообщено об ошибке

  • -xпараметр

Если вариант использования не выполняется или утверждение не выполняется, он немедленно прекращает выполнение и не выполняет последующие варианты использования.

  • --maxfailпараметр

Установите количество тестовых случаев, которые могут завершиться неудачно. При превышении этого порога выполнение будет остановлено.

pytest --maxfail=num ,неудачаиспользоватьпример数>=numчас,Хватит бежать

  • -mпараметр

Запуск всех вариантов использования, содержащих определенный тег, в соответствии с именем тега.,нуждатьсясуществоватьтестиспользоватьпримервыше Вседобавить декоратор@pytest.mark.отметкаимя。использовать-mПараметры,Можетделать表达式指Конечномногоиндивидуальныйотметкаимя。использовать-m "mark1 and mark2"Можеттакой жечасвыбиратьсерединаприноситьиметьэтот两индивидуальныйотметкаизвсетестиспользоватьпример。использовать-m "mark1 and not mark2"则встречавыбиратьсерединаприноситьmark1отметка И не приноси этоmark2отметкаизтестиспользоватьпример,использовать-m "mark1 or mark2"则встречавыбиратьсерединаприноситьиметьmark1илиmark2извсетестиспользоватьпример。

Теги вариантов использования используются следующим образом:

Язык кода:javascript
копировать
import pytest
@pytest.mark.mark1
@pytest.mark.mark2
def test_a002(self):
    print('this is test_a002 method')

использовать-mпараметрбегатьчас,Возможно, что намекать

Подвести итог

pytestпредоставляет основной наборизпроизводительные силы Функция,Может фильтровать и оптимизировать тест,Также существует гибкая система изплагина.,Можетдальше扩展其价ценить。несмотря ни на чтонасдаиметьодиногромныйизнаследиеunittestнабор,Все еще нужно начать новый проект?,pytestВсе能длянас Предложите многоизпомощь。

существоватьв этой статье,Юн Дуоцзюнь и все научились использовать:

  • Используется для обработки тестовых зависимостей.、состояниеи Может Тяжелыйиспользовать Функцияизfixture
  • вернотеструководить分добрый并限системаверновнешние ресурсыиздоступизотметка
  • использовать В减少тест之междуповторитькодизпараметризменять
  • правильный Конечнонассамый медленныйизтестизпродолжительность
  • использовать В与другойрамкаитестинструментинтегрированныйизплагин

Ссылки

[1]

fixture: https://docs.pytest.org/en/latest/fixture.html

[2]

Django: https://www.djangoproject.com/

[3]

monkeypatch: https://docs.pytest.org/en/latest/monkeypatch.html

[4]

pytest-django: https://pytest-django.readthedocs.io/en/latest/

[5]

parametrize: http://doc.pytest.org/en/latest/example/parametrize.html

[6]

pytest-randomly: https://github.com/pytest-dev/`pytest-randomly

[7]

coverage: https://coverage.readthedocs.io/

[8]

pytest-cov: https://pytest-cov.readthedocs.io/en/latest/

[9]

pytest-django: https://pytest-django.readthedocs.io/en/latest/

[10]

RequestFactory: https://docs.djangoproject.com/en/3.0/topics/testing/advanced/#django.test.RequestFactory

[11]

pytest-bdd: https://pytest-bdd.readthedocs.io/en/latest/

[12]

Gherkin: http://docs.behat.org/en/v2.5/guides/1.gherkin.html

[13]

Список сторонних плагинов: http://plugincompat.herokuapp.com/

[14]

d6tjoin: https://github.com/d6t/d6tjoin

boy illustration
Углубленный анализ переполнения памяти CUDA: OutOfMemoryError: CUDA не хватает памяти. Попыталась выделить 3,21 Ги Б (GPU 0; всего 8,00 Ги Б).
boy illustration
[Решено] ошибка установки conda. Среда решения: не удалось выполнить первоначальное зависание. Повторная попытка с помощью файла (графическое руководство).
boy illustration
Прочитайте нейросетевую модель Трансформера в одной статье
boy illustration
.ART Теплые зимние предложения уже открыты
boy illustration
Сравнительная таблица описания кодов ошибок Amap
boy illustration
Уведомление о последних правилах Points Mall в декабре 2022 года.
boy illustration
Даже новички могут быстро приступить к работе с легким сервером приложений.
boy illustration
Взгляд на RSAC 2024|Защита конфиденциальности в эпоху больших моделей
boy illustration
Вы используете ИИ каждый день и до сих пор не знаете, как ИИ дает обратную связь? Одна статья для понимания реализации в коде Python общих функций потерь генеративных моделей + анализ принципов расчета.
boy illustration
Используйте (внутренний) почтовый ящик для образовательных учреждений, чтобы использовать Microsoft Family Bucket (1T дискового пространства на одном диске и версию Office 365 для образовательных учреждений)
boy illustration
Руководство по началу работы с оперативным проектом (7) Практическое сочетание оперативного письма — оперативного письма на основе интеллектуальной системы вопросов и ответов службы поддержки клиентов
boy illustration
[docker] Версия сервера «Чтение 3» — создайте свою собственную программу чтения веб-текста
boy illustration
Обзор Cloud-init и этапы создания в рамках PVE
boy illustration
Корпоративные пользователи используют пакет регистрационных ресурсов для регистрации ICP для веб-сайта и активации оплаты WeChat H5 (с кодом платежного узла версии API V3)
boy illustration
Подробное объяснение таких показателей производительности с высоким уровнем параллелизма, как QPS, TPS, RT и пропускная способность.
boy illustration
Удачи в конкурсе Python Essay Challenge, станьте первым, кто испытает новую функцию сообщества [Запускать блоки кода онлайн] и выиграйте множество изысканных подарков!
boy illustration
[Техническая посадка травы] Кровавая рвота и отделка позволяют вам необычным образом ощипывать гусиные перья! Не распространяйте информацию! ! !
boy illustration
[Официальное ограниченное по времени мероприятие] Сейчас ноябрь, напишите и получите приз
boy illustration
Прочтите это в одной статье: Учебник для няни по созданию сервера Huanshou Parlu на базе CVM-сервера.
boy illustration
Cloud Native | Что такое CRD (настраиваемые определения ресурсов) в K8s?
boy illustration
Как использовать Cloudflare CDN для настройки узла (CF самостоятельно выбирает IP) Гонконг, Китай/Азия узел/сводка и рекомендации внутреннего высокоскоростного IP-сегмента
boy illustration
Дополнительные правила вознаграждения амбассадоров акции в марте 2023 г.
boy illustration
Можно ли открыть частный сервер Phantom Beast Palu одним щелчком мыши? Супер простой урок для начинающих! (Прилагается метод обновления сервера)
boy illustration
[Играйте с Phantom Beast Palu] Обновите игровой сервер Phantom Beast Pallu одним щелчком мыши
boy illustration
Maotouhu делится: последний доступный внутри страны адрес склада исходного образа Docker 2024 года (обновлено 1 декабря)
boy illustration
Кодирование Base64 в MultipartFile
boy illustration
5 точек расширения SpringBoot, супер практично!
boy illustration
Глубокое понимание сопоставления индексов Elasticsearch.
boy illustration
15 рекомендуемых платформ разработки с нулевым кодом корпоративного уровня. Всегда найдется та, которая вам понравится.
boy illustration
Аннотация EasyExcel позволяет экспортировать с сохранением двух десятичных знаков.