Skip to content

Latest commit

 

History

History
489 lines (375 loc) · 31.2 KB

test.md

File metadata and controls

489 lines (375 loc) · 31.2 KB

ya test

Команда ya test предназначена для тестирования программных проектов.

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

Основные возможности команды ya test:

  • Запуск тестов — выполняет тесты, указанные в проекте.
  • Описание тестов — тесты описываются в файле ya.make, где можно указать зависимости, параметры, теги и требования к ресурсам.
  • Вывод результатов — сохраняет результаты тестов, предоставляет информацию о пройденных и неудачных тестах.
  • Отладка — включает режимы отладки для детального анализа проблем.
  • Фильтрация тестов — позволяет запускать только выбранные тесты по имени, тегам, размеру и типу.

Команда ya test -h или --help выводит справочную информацию. Используйте -hh для отображения дополнительных опций и -hhh для получения еще более детальной информации.

Общий синтаксис команды

ya test [OPTION]… [TARGET]…

Параметры:

  • [OPTION] — параметры, уточняющие, как должны быть выполнены тесты (выбор конкретных тестов, вывод результатов и т.д.). Можно указывать несколько опций через пробел.
  • [TARGET] — аргументы, определяющие конкретные цели тестирования (имена тестовых наборов или индивидуальных тестов). Можно указать несколько целей через пробел.

Основные понятия

  • Test — индивидуальная проверка кода на корректность, стандарты оформления и устойчивость к ошибкам.
  • Chunk — группа тестов, выполняемых как единственный узел в графе команд сборки.
  • Suite — коллекция тестов одного типа с общими зависимостями и параметрами.

Взаимосвязь между понятиями

  • Тесты объединяются в Chunk на основе общей логики и последовательности выполнения.
  • Chunks группируются в Suite, который предоставляет контексты и параметры для всех входящих в него тестов.
  • Suite является основной единицей для запуска и фильтрации тестов, а также отслеживания зависимостей и ошибок.

Описание тестов

Тесты описываются в файле ya.make.

Можно использовать макросы и опции для задания параметров и зависимостей:

  • DEPENDS(path1 [path2...]) — указывает зависимости проекта, которые необходимы для запуска тестов.
  • SIZE(SMALL | MEDIUM | LARGE) — определяет размер теста, что помогает в управлении временем выполнения и ресурсами (значения: SMALL, MEDIUM, LARGE).
  • TIMEOUT(time) — устанавливает максимальное время выполнения теста.
  • TAG(tag1 [tag2...]) — добавляет теги к тестам, что помогает в их категоризации и фильтрации.
  • REQUIREMENTS() — указывает требования к ресурсам для выполнения тестов, такие как количество процессоров, объем памяти, использование диска и т.д.
  • ENV(key=[value]) — устанавливает переменные окружения, нужные для выполнения тестов.
  • SKIP_TEST(Reason) — отключает все тесты в модульной сборке. Параметр Reason указывает причину отключения.

Рекомендации по описанию тестов для различных языков программирования

Тестирование для C++

В настоящее время поддерживаются два основных тестовых фреймворка для тестирования на языке C++:

  1. unittest — собственная разработка.
  2. gtest — популярное решение от Google.

В дополнение к этим фреймворкам, имеется отдельная библиотека library/cpp/testing/common, содержащая полезные утилиты, которые не зависят от конкретного фреймворка.

Для бенчмаркинга используется библиотека google benchmark и модуль G_BENCHMARK.

Помимо метрик от бенчмарков, можно также сообщать числовые метрики из тестов, написанных с помощью UNITTEST() и GTEST(). Для добавления метрик используйте функцию testing::Test::RecordProperty, если работаете с gtest, или макрос UNIT_ADD_METRIC, если работаете с unittest.

Пример объявления метрик в gtest:

  TEST(Solver, TrivialCase) {
      // ...
      RecordProperty("num_iterations", 10);
      RecordProperty("score", "0.93");
  }

Пример объявления метрик в unittest:

  Y_UNIT_TEST_SUITE(Solver) {
      Y_UNIT_TEST(TrivialCase) {
          // ...
          UNIT_ADD_METRIC("num_iterations", 10);
          UNIT_ADD_METRIC("score", 0.93);
      }
  }

Для написания тестов вам потребуется создать ya.make файл с минимальной конфигурацией:

UNITTEST() | GTEST() | G_BENCHMARK()

SRCS(tests.cpp)

END()

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

Основным фреймворком для написания тестов на Python является pytest.

Поддерживаемые версии Python:

  • Python 2 (используется макрос PY2TEST, но считается устаревшим).
  • Python 3 (используется макрос PY3TEST).
  • Python 2/3 совместимые тесты (используется макрос PY23_TEST).

Все тестовые файлы перечисляются в макросе TEST_SRCS().

Пример конфигурационного файла ya.make:

PY3TEST() # Используем pytest для Python 3 (PY2TEST будет означать Python 2)

PY_SRCS( # Зависимости тестов, например, абстрактный базовый класс теста
    base.py
)

TEST_SRCS( # Перечисление всех файлов с тестами
    test.py
)

SIZE(MEDIUM)

END()

Чтобы сообщить метрики из теста, необходимо использовать funcarg metrics.

def test(metrics):
    metrics.set("name1", 12)
    metrics.set("name2", 12.5)

Для программ, собранных с использованием макросов PY2_PROGRAM, PY3_PROGRAM, PY2TEST, PY3TEST, PY23_TEST, автоматически выполняется импорт-тест:

  • Проверка корректности импортов позволяет выявить конфликты и отсутствующие зависимости.
  • Импорт-тест может быть отключен с помощью макроса NO_CHECK_IMPORTS().

Пример отключения проверки:

PY3TEST()

PY_SRCS(
    base.py
)

TEST_SRCS(
    test.py
)

SIZE(MEDIUM)

NO_CHECK_IMPORTS() # Отключить проверку импортируемости библиотек из PY_SRCS

NO_CHECK_IMPORTS( # Отключить проверку импортируемости только в указанных модулях
    devtools.pylibrary.*
)

END()

Бывает, что в библиотеках есть импорты, которые происходят по какому-то условию:

if sys.platform.startswith("win32"):
    import psutil._psmswindows as _psplatform

Если импорт-тест падает в таком месте, можно отключить его следующим образом:

NO_CHECK_IMPORTS( # Отключить проверку
    psutil._psmswindows
)

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

Для тестирования проектов на Java в данной системе используются фреймворки JUnit версий 4.x и 5.x.

Тестовый модуль для JUnit4 описывается модулем JTEST() или JTEST_FOR(path/to/testing/module).

  • JTEST() — система сборки будет искать тесты в JAVA_SRCS() данного модуля.
  • JTEST_FOR(path/to/testing/module) — система сборки будет искать тесты в тестируемом модуле.

Для включения JUnit5 вместо JTEST() необходимо использовать JUNIT5().

Настройка тестирования осуществляется посредством ya.make файлов.

Минимальный ya.make файл выглядит так:

  • JUnit4
    JTEST()
    
    JAVA_SRCS(FileTest.java)
    
    PEERDIR(
      # Сюда же необходимо добавить зависимости от исходных кодов вашего проекта
      contrib/java/junit/junit/4.12 # Сам фреймворк JUnit 4
      contrib/java/org/hamcrest/hamcrest-all # Можно подключить набор Hamcrest матчеров
    )
    
    END()
    
  • JUnit5
    JUNIT5()
    JAVE_SRCS(FileTest.java)
    PEERDIR(
      # Сюда же необходимо добавить зависимости от исходных кодов вашего проекта
      contrib/java/org/junit/jupiter/junit-jupiter # Сам фреймворк JUnit 5
      contrib/java/org/hamcrest/hamcrest-all # Набор Hamcrest матчеров
    )
    END()
    

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

Тестирование в Go базируется на стандартном инструментарии для Go. Для работы с зависимостями теста рекомендуется использовать библиотеку library/go/test/yatest.

Все тестовые файлы должны иметь суффикс _test.go. Они указываются в макросе GO_TEST_SRCS.

Тестовый модуль описывается модулем GO_TEST() или GO_TEST_FOR(path/to/testing/module).

  • GO_TEST() — система сборки будет искать тесты в GO_TEST_SRCS() данного модуля.
  • GO_TEST_FOR(path/to/testing/module) — система сборки будет искать тесты в GO_TEST_SRCS в тестируемом модуле.

Минимальные ya.make файлы выглядят так:

  • GO_TEST()

    GO_TEST()
    
    GO_TEST_SRCS(file_test.go)
    
    END()
    
  • GO_TEST_FOR()

    В project/ya.make в макросе GO_TEST_SRCS перечисляются тестовые файлы:

    GO_LIBRARY() | GO_PROGRAM()
    
    SRCS(file.go)
    
    GO_TEST_SRCS(file_test.go)
    
    END()
    
    RECURSE(tests)
    

Запуск тестов

При запуске тестов в локальной среде разработки необходимо учитывать несколько ключевых моментов.

  • Все тесты запускаются в режиме отладки (debug).
  • Таймаут выполнения тестов зависит от их размеров: SMALL, MEDIUM или LARGE.
  • Результаты тестов сохраняются в директорию test-results. Внутри нее находятся поддиректории с логами и файлами, порожденными тестами.
  • Если тесты завершились неуспешно, в консоль выводится информация о путях к результатам.

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

Для простого запуска тестов есть следующие ключи командной строки:

  • -t — запустить только SMALL тесты.
  • -tt — запустить SMALL и MEDIUM тесты.
  • -ttt, -A, --run-all-tests — запустить тесты всех размеров.
  • --test-param=TEST_PARAM — параметризовать тесты значениями из командной строки. TEST_PARAM имеет вид name=val, доступ к параметрам зависит от используемого фреймворка.
  • --retest — принудительный перезапуск тестов без использования кеша.

Пример

$ ya test -t devtools/examples/tutorials/python

Запустит все тесты, которые найдет по RECURSE/RECURSE_FOR_TESTS от devtools/examples/tutorials/python, включая тесты стиля и тесты импорта для Python.

Использует следующие умолчания для сборки:

  • Платформа будет определена по реальной платформе, на которой запущена команда ya test.
  • Тесты будут собраны в режиме debug — он используется по умолчанию.
  • Кроме тестов будут собраны все остальные цели (библиотеки и программы), достижимые по RECURSE/RECURSE_FOR_TESTS от devtools/examples/tutorials/python. Это включает сборку всех необходимых зависимостей.

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

Управление выводом результатов

Команда ya test предоставляет несколько опций для управления выводом результатов тестирования.

Эти опции позволяют контролировать объем информации, которые возвращаются после запуска тестов, и помогают быстрее находить и исправлять ошибки:

  • -L, --list-tests — выводит список тестов, которые будут выполнены.
ya test -tL
  • --fail-fast — завершает выполнение тестов при первой неудаче.
ya test -t --fail-fast
  • -P, --show-passed-tests — показать пройденные тесты.
ya test -t --show-passed-tests
  • --show-skipped-tests — показать пропущенные тесты.
  • --show-metrics — показать метрики тестов.

В конце выполнения тестов для всех упавших тестов будет выдана краткая информация о невыполнении (включая ссылки на более полную информацию). Для прошедших и проигнорированных (отфильтрованных) тестов будет выдан только общий короткий статус с количеством тех и других тестов.

Примеры полного отчета при использовании различных опций:

ya test -t --show-passed-tests --show-skipped-tests --show-metrics

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

Пример

# Список всех пользовательских тестов (без тестов стиля, импортов и подобных проверок)
ya test -AL --regular-tests devtools/examples/tutorials/python

Команда ya test поддерживает параллельный запуск тестов.

Отладка

Команда ya test предлагает несколько опций для отладки:

  • --test-debug — включить режим отладки тестов (PID, дополнительные параметры).
  • --pdb, --gdb, --dlv — запустить тесты с интеграцией в различные отладчики (для Python, C++, Go).

Выборочное тестирование

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

Фильтрация тестов:

  1. -F=TESTS_FILTERS, --test-filter=TESTS_FILTERS — запуск только определенных тестов по имени, шаблону или фильтру.
ya test -A -F "subname"

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

$ ya test -t -F <file>.py::<ClassName>::*
  1. --test-tag=TEST_TAGS_FILTER — запуск тестов, помеченных определенными тегами.
ya test -A --test-tag tag1+tag2-tag3

Эта команда запустит все тесты, у которых есть теги tag1 и tag2 и нет тега tag3.

  1. --test-size=TEST_SIZE_FILTERS — запуск тестов определенного размера (SMALL, MEDIUM, LARGE).
ya test -A --test-size=MEDIUM
  1. --test-type=TEST_TYPE_FILTERS — запуск тестов определенного типа (например, UNITTEST, PYTEST).
ya test -tt --test-type unittest+gtest

Эта команда запустит только тесты типов unittest и gtest.

  1. --test-filename=TEST_FILES_FILTER — запуск тестов из указанного исходного файла.
ya test -A --test-filename=test_example.py
  1. -X, --last-failed-tests — запустить только тесты, упавшие в предыдущем запуске.
  2. --regular-tests — запустить только пользовательские тесты.
  3. --style — запустить только тесты стиля.

Проверки кода и корректности данных

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

Python

Для языка Python, flake8 автоматически проверяет стиль кода для всех подключенных через ya.make файлов в секциях PY_SRCS и TEST_SRCS, включая плагины для проверки длины строки до 200 символов и игнорирование ошибок с помощью комментариев # noqa или # noqa: E101. Ошибку F401 можно подавить в файле __init__.py с помощью # flake8 noqa: F401. Для директории contrib можно отключить проверку стиля через макрос NO_LINT().

Для проектов на Python 3 линтер black подключается с помощью макроса STYLE_PYTHON(), который генерирует тесты для проверки стиля кода. Запустить тесты black можно командой:

ya test -t --test-type black.

Импорт-тесты проверяют импортируемость программ Python, собранных из модулей, обнаруживая конфликты и отсутствующие файлы. Эти проверки называются import_test, они не являются style-тестами, так как такие тесты требуют сборку. Отключить проверку стиля можно с помощью NO_CHECK_IMPORTS, указав конкретные исключения.

Java

Для исходных файлов на Java, стиль кода проверяется утилитой checkstyle на обычном и строгом уровнях, последний включается макросом LINT(strict), а конфигурационные файлы хранятся в директории resource. Опционально можно проверить наличие дублирующихся классов в classpath с помощью макроса CHECK_JAVA_DEPS(yes).

Kotlin

Проекты на Kotlin автоматически проверяются утилитой ktlint для стиля кода. Проверку можно отключить через макрос NO_LINT(ktlint) в файле сборки, а исключения можно добавить через макрос KTLINT_BASELINE_FILE.

Go

Для проектов на Go используются инструменты gofmt для проверки стиля кода и govet для статического анализа подозрительных конструкций и антипаттернов.

C++

Для кода на C++ применяется clang-tidy, который используется для статического анализа. Его можно запустить с флагом ya test -t -DTIDY.

Пример ya.make файла с проверками стиля может выглядеть так:

PY3_LIBRARY()

PY_SRCS(
    src/init.py
    src/module.py
)

STYLE_PYTHON()

NO_CHECK_IMPORTS(
    devtools.pylibrary.
)

END()

Канонизация (и переканонизация)

Для некоторых типов тестов в системе сборки поддерживается механизм сравнения с эталонными (каноническими) данными.

  1. Канонические данные — эталонные данные, с которыми сравниваются результаты теста.
  2. Канонизация — процесс обновления эталонных данных для соответствия текущим результатам тестов.
  3. Переканонизация — повторная канонизация, проводимая для обновления эталонных данных после изменения тестов или их окружения. Если данные нужно обновить, воспользуйтесь опцией -Z (--canonize-tests).

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

Тесты с санитайзерами

Система позволяет собирать инструментированные программы с санитайзерами. Поддерживаются санитайзеры AddressSanitizer, MemorySanitizer, ThreadSanitizer, UndefinedBehaviorSanitizer и LeakSanitizer.

Запуск с санитайзером:

ya test -t --sanitize=address

Для правильной работы санитайзеров можно зафиксировать опции для конкретных тестов через макрос ENV().

Fuzzing

Фаззинг позволяет передавать приложению на вход неправильные, неожиданные или случайные данные. Автоматический фаззинг поддерживается через libFuzzer.

Пример запуска фаззинга:

ya test -r --sanitize=address --sanitize-coverage=trace-div,trace-gep -A --fuzzing

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

Запуск произвольных программ (Exec-тесты)

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

Описание таких тестов также осуществляется в файле ya.make.

EXECTEST()  # Объявление Exec-теста

RUN(  # Команда, которую хотим выполнить
    cat input.txt
)

DATA(  # Тестовые данные, которые необходимы для выполнения команды (здесь лежит input.txt)
    PROJECT/devtools/ya/test/tests/exectest/data
)

DEPENDS(  # Зависимость от других проектов (например, исходные коды cat)
    devtools/dummy_PROJECT/cat
)

# Текущий каталог для теста (каталог с input.txt)
TEST_CWD(devtools/ya/test/tests/exectest/data)

END()

Типы тестов

Типом теста называется выполнение проверок с использованием одного конкретного инструмента, например, фреймворка pytest для Python или утилиты проверки форматирования кода go fmt для Golang. Полный список типов тестов приведен в таблице:

Тип Описание
black Проверка форматирования кода на Python 3 утилитой black.
classpath.clash Проверка наличия дублирующихся классов в classpath при компиляции Java-проекта.
eslint Проверка стиля и типичных ошибок кода на TypeScript с использованием утилиты ESLint.
exectest Выполнение произвольной команды и проверка ее кода возврата.
flake8.py2 Проверка стиля кода на Python 2 c использованием утилиты Flake8.
flake8.py3 Проверка стиля кода на Python 3 c использованием утилиты Flake8.
fuzz Fuzzing тест.
g_benchmark Выполнение бенчмарков на C++ библиотекой Google Benchmark.
go_bench Выполнение бенчмарков на Go утилитой go bench.
gofmt Проверка форматирования кода на Go утилитой go fmt.
go_test Выполнение тестов на Go утилитой go test.
govet Выполнение статического анализатора кода на Go утилитой go vet.
gtest Выполнение тестов на С++ с использованием фреймворка Google Test.
java Выполнение тестов на Java с использованием фреймворка JUnit.
java.style Проверка форматирования кода на Java утилитой checkstyle.
ktlint Проверка стиля Kotlin кода с использованием утилиты ktlint.
py2test Тесты на Python 2 с использованием фреймворка pytest.
py3test Тесты на Python 3 с использованием фреймворка pytest.
pytest Тесты на Python любой версии с использованием фреймворка pytest.
unittest Тесты на C++ с использованием фреймворка unittest.