Как запускать тесты

Способы запуска тестов: из командной строки, автообнаружение и программный запуск.

Test discovery — механизм, которым unittest сам находит все файлы с тестами по соглашению об именах (test_*.py).

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

В реальном проекте тесты лежат в отдельных файлах и запускаются командой. Базовый способ — указать модуль с тестами:

# Запустить тесты из файла test_calc.py
python -m unittest test_calc

# Запустить конкретный класс
python -m unittest test_calc.TestAdd

# Запустить один конкретный тест
python -m unittest test_calc.TestAdd.test_positive

Флаг -v (verbose) включает подробный вывод — по строке на тест, как наш verbosity=2:

python -m unittest -v test_calc

Автообнаружение тестов

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

# Найти и запустить все test_*.py в текущей папке и подпапках
python -m unittest discover

# Указать стартовую папку и шаблон имён
python -m unittest discover -s tests -p "test_*.py"

Чтобы автообнаружение работало, придерживайтесь соглашений: файлы называются test_*.py, классы наследуются от TestCase, методы начинаются с test_. Это стандарт, которого ждёт инструмент.

Программный запуск (то, что работает прямо в браузере)

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

Способ 1: unittest.main

import unittest

def is_palindrome(s):
    s = s.lower()
    return s == s[::-1]

class TestPalindrome(unittest.TestCase):
    def test_true(self):
        self.assertTrue(is_palindrome("шалаш"))

    def test_false(self):
        self.assertFalse(is_palindrome("питон"))

# argv=[''] — не разбирать аргументы; exit=False — не завершать процесс
unittest.main(argv=[''], exit=False, verbosity=2)

Вывод:

test_false (__main__.TestPalindrome.test_false) ... ok
test_true (__main__.TestPalindrome.test_true) ... ok

----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

Способ 2: TextTestRunner и доступ к результату

Этот способ даёт объект с результатом, у которого можно спросить статус программно:

import unittest

class TestMath(unittest.TestCase):
    def test_add(self):
        self.assertEqual(1 + 1, 2)

    def test_mul(self):
        self.assertEqual(2 * 3, 6)

# Собираем набор тестов из класса
suite = unittest.TestLoader().loadTestsFromTestCase(TestMath)
result = unittest.TextTestRunner(verbosity=2).run(suite)

print("Успешно:", result.wasSuccessful())
print("Запущено тестов:", result.testsRun)

Вывод: (строки отчёта unittest идут в stderr, а print — в stdout; устойчивая часть)

Ran 2 tests in 0.000s

OK
Успешно: True
Запущено тестов: 2

Метод result.wasSuccessful() возвращает True/False — удобно для скриптов и CI, где по статусу решают, продолжать сборку или нет.

Памятка по запуску

КомандаЧто делает
python -m unittestзапускает обнаруженные тесты
python -m unittest discoverищет все test_*.py
python -m unittest -vподробный вывод (по строке на тест)
unittest.main(argv=[''], exit=False)программный запуск внутри кода

Где в проекте лежат тесты

Сложилось две распространённые раскладки. Первая — отдельная папка tests/ рядом с кодом, куда складывают все файлы test_*.py; именно её обходит discover. Вторая — тестовый файл рядом с тестируемым модулем (calc.py и test_calc.py в одной папке). Обе работают; для небольших проектов проще вторая, для крупных — отдельная папка tests/. Главное — единообразие и соблюдение префикса test_, иначе автообнаружение не найдёт файлы.

Как читать отчёт о прогоне

В конце прогона unittest печатает сводку: сколько тестов выполнено (Ran N tests), за какое время и итог — OK либо FAILED с разбивкой (failures=..., errors=...). При подробном выводе перед сводкой идёт по строке на каждый тест со статусом ok/FAIL/ERROR/skipped. Привыкайте сразу смотреть в конец отчёта: финальная строка отвечает на главный вопрос — «всё зелёное или нет». В CI именно эта строка определяет, прошла сборка или упала.

Итог

  • В проектах тесты запускают командой python -m unittest, флаг -v — подробнее.
  • discover сам находит файлы test_*.py — соблюдайте соглашения об именах.
  • Программно: unittest.main(argv=[''], exit=False) или TextTestRunner().run(suite).
  • result.wasSuccessful() даёт статус для скриптов и CI.
Проверьте себя
1. Что делает команда python -m unittest discover?
AУдаляет старые тесты
BАвтоматически находит и запускает файлы test_*.py
CСоздаёт новый тест
DПоказывает покрытие
2. Что возвращает result.wasSuccessful() после прогона?
AСписок упавших тестов
BTrue/False — успешен ли прогон
CВремя выполнения
DЧисло строк кода
3. Какой флаг включает подробный вывод (по строке на тест)?
A-q
B-v
C-x
D-s
Поддержать проект