Статья предполает, что вы знаете что такое Databricks, что такое ноутбуки, кластера и джобы (воркфлоус) в нём. Поиск по хабру предлагает вот эту статью для ознакомления. Я продолжаю серию статей, где анализирую свой текущий проект в области BigData. Первая статья была посвящена найму питонистов, вторая - проблемам внедрения новых процессов в распределённых командах. Однако помимо чисто управленческих задач, в проекте есть ряд технических сложностей. Одной из таких сложностей является тестирование платформы обработки данных. Если с тестированием более привычных программных продуктов более-менее ясно, то вот с BigData возникает множество вопросов. Если у вас Java - у вас есть как минимум JUnit, а абсолютное большинство фреймворков заботятся о простоте тестирования. Например Spring посвящает этому очень много документации. Тестирование фронтенда тоже хорошо проработано: от Selenium до JestJs. Тестировать блокчейн и смарт-контракты одно удовольствие (хотя бы на Ethereum сети благодаря Truffle Suite) На Питоне тоже есть свои фреймворки для тестирования и вопрос этот вполне себе проработан. Даже сам Databricks, на базе которого построена наша платформа обработки данных, предлагает свои пути для тестирования. Например вот неплохой официальный гайд по тестированию: Unit testing for notebooks. Однако нужно иметь репозиторий внутри самого Databricks. А у нас код хранится в корпоративном GitLab, который недоступен из нашего же Databricks. Очень неудобно, но отдел безопасности не даёт разрешения настроить доступ из внешнего ресурса во внутреннюю сеть. Есть возможность по тестированию прямо внутри ноутбуков Databricks: Test Databricks notebooks. Из минусов: сложность в организации кода, урезанный импорт ноутбуков внутри Databricks. Мы сделали несколько попыток тестировать нашу платформу и так, и сяк, но всё выходило весьма "велосипедно". И тут мы наткнулись и решили попробовать Nutter Framework. То, что он обещал очень подходило для наших потребностей. Респект Microsoft за такой тул в opensource. Главная цель данного фреймворка - дать возможность легко и быстро тестировать ноутбуки в Databricks. Nutter предлагает определённый подход к написанию тестов и несколько подходов к их выполнению. Во-первых, чтобы начать работать с тестами, необходимо поставить библиотеку nutter на тот кластер, где будут выполняться тестовые ноутбуки: Далее создаём ноутбук, импортируем базовый класс NutterFixture и начинаем писать тестовый класс: Чтобы выполнить и увидеть результаты выполнения тестов, запускаем сам тестовый класс: Тесты можно запускать через коммандную строку (см. ниже как это сделать). И чтобы вернуть результаты выполнения тестов в nutter-cli, нужно выполнить в конце ноутбука: Однако есть неприятное ограничение: внутри result.exit вызывает dbutils.notebook.exit() , что приводит к тому, что Databricks прячет все выводы от команд print . Поэтому если запускать тесты прямо ноутбуках, строчку с exit нужно закомментировать. Внутри одного тест-класса может быть несколько тестов. Каждый тест состоит из 1 обязательного метода и 3 дополнительных: before_(testname) - выполнятеся перед run Используется для настройки тестов и выполнения подготовительных действий. Необязателен. run_(testname) - выполняется после before (если он имеется) или первым. Тут должны быть действия, которые непосредственно тестируются, например вызов ноутбука. Необязателен. assertion_(testname) - выполняется после run (если он есть). Содержит проверки состояний. Можно использовать assert из любых питоновских тестовых библиотек. Каждый тест-класс должен содержать хотя бы 1 assertion-метод. after_(testname) - выполняется после assertion. Обычно используется, чтобы вернуть состояние тестовых объектов в исходное или "почистить" что-то после выполнения теста.  Пример: методы run_checkpoint_location_generation и assertion_checkpoint_location_generation будут трактоваться как 1 тест-кейс. Дополнительно есть два метода: before_all after_all Они выполняются соответственно до и после всех тестов. Если вы хотите использовать несколько отдельных assertion на 1 тест-кейс, тогда нужно использовать before_all и для подготовки теста и для вызова тестируемых действий.  Nutter гарантирует выполнение тестов в алфавитном порядке на основе имени тест-кейса. Также Nutter позволяет сохранять состояние и передавать данные между тест-кейсами через параметры конструктора: Когда тестов много, то хочется запускать их в несколько потоков и сократить время выполнения. Последняя версия Nutter`а (0.1.35) позволяет это сделать с помощью NutterFixtureParallelRunner : Резульаты тестов объединяются и показываются в удобном виде: Одна из главных фишек Nutter`а - это возможность запускать тесты из командной строки. Для начала установим Nutter через pip: Затем зададим 2 переменных окружения, чтобы предоставить доступ Databricks: Linux Windows PowerShell Для начала можно показать какие тесты могут быть исполнены: Получаем что-то такое: А теперь запустим какой-то конкретный тест: Эта команда запускает конкретный тест-класс на определённом кластере (на кластере должна быть установлены библиотека nutter) Чтобы запустить все тест-классы, можно использовать следующую команду Имена тестов должны начинаться с test_ Флаг --recursiveобеспечивает поиск тестовых классов рекурсивно во всех поддиректориях. Передавать какие-то параметры можно через опцию --notebook_params: Спасибо @raukasky за написание конкретных тест-классов для сервисов платформы. Такой тест-класс можно отнести к уровню интеграционного тестирования: сервис stream_delta_transformation проверяется в окружении, максимально приближенном к реальному. Мы не внедряем моки или "шпионские" объекты, проверки идут на реально созданных таблицах и данных. Тем не менее, мы можем проверить некоторые методы внутри сервиса по тем результатам, что они выдают по итогам работы сервиса. Например мы проверяем, что целевые таблицы создаются, что они находятся в правильном месте (потому что все таблицы у нас external), и так далее. Кроме проверок работы конкретных методов, мы можем прочитать данные из целевой таблицы и проверить, что трансформация данных прошла корректно. Пока мы запускаем это вручную из командной строки, но это уже огромный шаг вперёд для того, чтобы обеспечить интеграционное тестирование. А так как это вполне себе обычный python-код, то это открывает возможности проверки всего, что делают сервисы. Например, вполне реально написать тест на проверку публикации данных из Delta Lake в MySql, потому что в тестовом классе мы можем обратить в MySql напрямую и проверить, что там оказалось. Итак, Nutter Framework позволил нашей команде: проводить интеграционное тестирование сервисов, написанных как ноутбуки в Databricks; запускать тесты как прямо в ноутубках в Databricks, так и из командной строки; написать набор регрессионных тестов на отдельные методы сервисов. Не так удобно как чистые unit-тесты, но значительно лучше, чем ничего. Время проведения регрессионного тестирования значительно снизилось. В дальнейшем мы планируем внедрить запуск тестов в процесс сборки и деплоя платформы, непосредственно в GitLab CI/CD. Как это делать для Azure есть в официальной документации. Для нашего проекта Nutter стал отличным выбором и очень удобным инструментом тестирования. В конце этой статьи хочу порекомендовать вам полезный вебинар от OTUS, где расскажут о профессии автоматизатора тестирования, об актуальных технологиях, пользе использования автотестов, а так же о нужных навыках и особенностях собеседований. Регистрация на вебинар доступна по ссылке