Рубрики
Без рубрики

Устройство тестирования Python Code в ноутбуках Jupyter

Большинство из нас согласны с тем, что мы должны писать модульные тесты, и многие из нас на самом деле делают. Это должно быть особенным … Теги с Python.

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

Часто Jupyter Notebooks с Python используются для разведки данных, и поэтому пользователи могут не выбирать (или нужно) писать тесты подразделения для их ноутбука, поскольку они обычно могут рассматривать результаты для каждой ячейки, поскольку они прогрессируют через ноутбук, затем вывод и двигаться дальше. Однако в моем опыте того, что обычно происходит с ноутбуками, вскоре код в ноутбуке перемещается за пределы разведки данных и полезно для дальнейшей работы. Или, возможно, сам тетрадь производит результаты, которые полезны и должны работать на регулярной основе. Возможно, код должен поддерживаться и интегрироваться с внешними источниками данных. Тогда становится важно обеспечить, чтобы код в ноутбуке можно проверить и проверить.

В этом случае каковы наши варианты для тестирования модуля тетради? В этой статье я охвачу несколько вариантов для тестирования блока Python Code в ноутбуке Jupyter.

Может быть, просто не делай этого?

Первый вариант тестирования ноутбука Jupyter – просто не делать это вообще. Этим, я не имею в виду, не проверяйте свой код, а скорее Экстракт Это из ноутбука в отдельные модули Python, которые вы импортируете обратно в свою ноутбук. Этот код должен быть проверен таким образом, как вы обычно смотритете свой код, будь то с Неизвестный , pteest , доктра или другая структура тестирования единицы. Эта статья не будет охватывать все эти рамки подробно, но отличный выбор для разработчиков Python – не тестировать внутри своих ноутбуков Jupyter, но использовать богатый ассортимент структур тестирования, уже доступных для кода Python, и переместить код на внешние модули Как можно скорее в процессе развития.

Хорошо, так что вы можете проверить в ноутбуке

Если вы в конечном итоге решите, вы хотите оставить свой код внутри ноутбука Jupyter, на самом деле есть некоторые параметры тестирования единиц. Перед просмотром нескольких из них давайте просто настроим примеру кода, который мы могли бы встретить в ноутбуке Jupyter. Допустим, ваша ноутбук вытягивает некоторые данные из API, вычисляет некоторые результаты из него, затем производит некоторые графики и другие сводки данных, которые оно сохраняется в другом месте. Возможно, есть функция, которая производит правильный URL-адрес API, и мы хотим установить тестирование этой функции. Эта функция имеет некоторую логику, которая изменяет формат URL на основе даты для отчета. Вот отлаженная версия.

import datetime
import dateutil

def make_url(date):
    """Return the url for our API call based on date."""

    if isinstance(date, str):
        date = dateutil.parser.parse(date).date()
    elif not isinstance(date, datetime.date):
        raise ValueError("must be a date")
    if date >= datetime.date(2020, 1, 1):
        return f"https://api.example.com/v2/{date.year}/{date.month}/{date.day}"
    else:
        return f"https://api.example.com/v1/{date:%Y-%m-%d}"

Устройство тестирования с ненужденным

Обычно, когда мы тестируем с Неизвестный Мы либо поместили наши методы испытаний в отдельном тестовом модуле, либо, возможно, мы смешиваем эти методы внутри основного модуля. Тогда нам нужно будет выполнить Unittest.main Метод, возможно, как метод по умолчанию внутри __main__ сторожить. Мы можем в основном сделать то же самое в нашей ноутбуке Jupyter. Мы можем сделать единица. Testcase Класс, выполните тесты, которые мы хотим, а затем просто выполнить тесты подразделения в любой ячейке. Результаты испытаний могут даже быть проверены или утверждены, чтобы включить никаких сбоев, если вы хотите выполнить выполнение ноутбука, чтобы выйти из ошибок. Вам просто нужно сохранить вывод Unittest.main Метод и проверьте его на ошибки.

import unittest

class TestUrl(unittest.TestCase):
    def test_make_url_v2(self):
        date = datetime.date(2020, 1, 1)
        self.assertEqual(make_url(date), "https://api.example.com/v2/2020/1/1")

    def test_make_url_v1(self):
        date = datetime.date(2019, 12, 31)
        self.assertEqual(make_url(date), "https://api.example.com/v1/2019-12-31")


res = unittest.main(argv=[''], verbosity=3, exit=False)

# if we want our notebook to stop processing due to failures, we need a cell itself to fail
assert len(res.result.failures) == 0
test_make_url_v1 ( __main__.TestUrl) ... ok
test_make_url_v2 ( __main__.TestUrl) ... ok

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

OK

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

Устройство тестирования со довержем

Другой способ включить тесты в вашем коде – использовать доктра Отказ DATEST использует специально отформатированную документацию кода, которая включает в себя наши тесты и ожидаемые результаты. Ниже приведен обновленный метод с этой специальной документацией кода, включенной как для положительных, так и для отрицательных тестов. Это простой способ тестирования и кода документов в одном месте, и часто будет использоваться в модулях Python, где главная гвардия просто будет запустить докторскую тему, как это:

if __name__ == __main__ :
    doctest.testmod()

Поскольку мы в ноутбуке, мы просто добавим это к ячейке ниже, где определен наш код, и он также будет работать. Во-первых, вот наш обновленный make_url Метод с доктором комментариев.

def make_url(date):
    """Return the url for our API call based on date.
    >>> make_url("1/1/2020")
    'https://api.example.com/v2/2020/1/1'

    >>> make_url("1-1-x1")
    Traceback (most recent call last):
        ...
    dateutil.parser._parser.ParserError: Unknown string format: 1-1-x1

    >>> make_url("1/1/20001")
    Traceback (most recent call last):
        ...
    dateutil.parser._parser.ParserError: year 20001 is out of range: 1/1/20001

    >>> make_url(datetime.date(2020,1,1))
    'https://api.example.com/v2/2020/1/1'

    >>> make_url(datetime.date(2019,12,31))
    'https://api.example.com/v1/2019-12-31'
    """
    if isinstance(date, str):
        date = dateutil.parser.parse(date).date()
    elif not isinstance(date, datetime.date):
        raise ValueError("must be a date")
    if date >= datetime.date(2020, 1, 1):
        return f"https://api.example.com/v2/{date.year}/{date.month}/{date.day}"
    else:
        return f"https://api.example.com/v1/{date:%Y-%m-%d}"

import doctest
doctest.testmod()

TestResults(failed=0, attempted=5)

Устройство тестирования с тестовой книгой

Тестовая книга Проект – это другое. Это позволяет ссылаться на ваши ноутбуки в чистом виде Python из внешнего ноутбука. Это позволяет вам использовать любую систему тестирования, которые вам нравятся (например, Pteest или Unittest ) в отдельных модулях Python. У вас может быть ситуация, когда позволяет пользователям изменять и обновлять код ноутбука – лучший способ сохранить обновление кода и, чтобы обеспечить гибкость для конечных пользователей. Но вы можете предпочесть, чтобы код все еще был проверен и проверен отдельно. TestBook делает этот вариант.

Во-первых, вы должны установить его в свою среду:

pip install testbook

или В вашей записной книжке

%pip install testbook

Теперь в отдельном файле Python вы можете импортировать код ноутбука и проверить его там. В этом файле вы создадите код, который выглядит следующим образом, а затем вы будете использовать какую бы структуру тестирования подразделения, вы предпочитаете фактически выполнить тест устройства. Вы можете создать следующий код в файле Python (скажем, Jupyter_unit_tests.cy ).

import datetime
import testbook

@testbook.testbook('./jupyter_unit_tests.ipynb', execute=True)
def test_make_url(tb):
    func = tb.ref("make_url")
    date = datetime.date(2020, 1, 2)
    assert make_url(date) == "https://api.example.com/v2/2020/1/1"

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

pytest jupyter_unit_tests.py

Это работает как нормальный тест на единицу, а тесты должны пройти. Однако в разработке этой статьи я понял, что Тестовая книга Код имеет ограниченную поддержку для передачи аргументов в тестите устройства обратно в ядро ноутбука для тестирования. Эти аргументы являются JSON Serialized, и текущий код знает, как обрабатывать широкий массив типов Python. Но это не передает dateTime в качестве объекта, например, но как строка. Поскольку наш код делает попытку разбираться на строки в даты (после того, как я его изменил), это работает. Другими словами, тестирование подразделения выше не передается в datetime.date к make_url Метод, а скорее строка ( 2020-01-02 ), который затем проанализируется в дату. Как вы можете пройти на дату от тестирования подразделения в код ноутбука? У вас есть несколько вариантов. Во-первых, вы можете сделать объект даты в вашем ноутбуке только для целей тестирования, а затем обратиться к этому в тестах вашего устройства.

testdate1 = datetime.date(2020,1,1) # for unit test

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

Второй вариант – ввести код Python в ноутбук, затем обратитесь к нему в тесте вашего устройства. Оба варианта отображаются в окончательной версии теста внешнего блока. Просто сохраните это за jupyter_unit_tests.cy и запустить его, используя свою любимую структуру тестирования подразделения.

import datetime

import testbook

@testbook.testbook('./jupyter_unit_tests.ipynb', execute=True)
def test_make_url(tb):
    f = tb.ref("make_url")
    d = "2020-01-02"
    assert f(d) == "https://api.example.com/v2/2020/1/2"

    # note that this is actually converted to a string
    d = datetime.date(2020, 1, 2)
    assert f(d) == "https://api.example.com/v2/2020/1/2"

    # this one will be testing the date functionality
    d2 = tb.ref("testdate1")
    assert f(d2) == "https://api.example.com/v2/2020/1/1"

    # this one will inject similar code as above, then use it
    tb.inject("d3 = datetime.date(2020, 2, 3)")
    d3 = tb.ref("d3")
    assert f(d3) == "https://api.example.com/v2/2020/2/3"

Резюме

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

Пост Устройство тестирования Python код в ноутбуках Jupyter появился первым на Wrighters.io Отказ

Оригинал: “https://dev.to/wrighter/unit-testing-python-code-in-jupyter-notebooks-32l6”