Пропуск тестов и группировка
Как пропускать тесты, помечать известные баги и группировать тесты в наборы.
skip — пометка «не выполнять этот тест сейчас». expectedFailure — «этот тест должен падать (известный баг), и это не ошибка сборки».
Пропуск тестов: skip
Иногда тест нельзя или не нужно запускать: фича ещё не готова, тест зависит от платформы, нужна версия библиотеки. Вместо удаления или комментирования его пропускают — тогда он остаётся в отчёте как «skipped», а не теряется.
@unittest.skip("причина")— всегда пропустить.@unittest.skipIf(условие, "причина")— пропустить, если условие истинно.@unittest.skipUnless(условие, "причина")— пропустить, если условие ложно.
expectedFailure: известный, но ещё не исправленный баг
Если вы знаете о баге, но пока не можете его починить, тест на него будет падать и «портить» зелёную сборку. Декоратор @unittest.expectedFailure говорит: «я знаю, что тут падает». Тест считается ожидаемо упавшим — сборка остаётся зелёной. А если он вдруг пройдёт, unittest пометит это как unexpected success — сигнал «баг починили, убери пометку».
Запускаемый пример
import unittest
class TestStatuses(unittest.TestCase):
def test_normal(self):
self.assertEqual(2 + 2, 4)
@unittest.skip("ещё не реализовано")
def test_future_feature(self):
self.fail("этот код не выполнится")
@unittest.skipIf(1 > 0, "пропускаем по условию")
def test_conditional(self):
self.fail("и этот тоже пропущен")
@unittest.expectedFailure
def test_known_bug(self):
# Известный баг: пока ждём 2, но получаем 3
self.assertEqual(1 + 2, 2)
unittest.main(argv=[''], exit=False, verbosity=2)
Вывод: (важна итоговая строка со сводкой статусов)
test_conditional ... skipped 'пропускаем по условию' test_future_feature ... skipped 'ещё не реализовано' test_known_bug ... expected failure test_normal ... ok ---------------------------------------------------------------------- Ran 4 tests in 0.001s OK (skipped=2, expected failures=1)
Сборка зелёная (OK), хотя один тест помечен как «ожидаемо падающий», а два пропущены. Всё это видно в отчёте — ничего не потерялось.
Группировка тестов: TestSuite
Обычно unittest сам собирает тесты. Но иногда нужно вручную составить набор (suite) из конкретных тестов — например, «быстрый прогон» только важных проверок. Для этого есть TestSuite:
import unittest
class TestMath(unittest.TestCase):
def test_add(self):
self.assertEqual(1 + 1, 2)
def test_sub(self):
self.assertEqual(5 - 2, 3)
def test_mul(self):
self.assertEqual(2 * 3, 6)
# Собираем набор вручную: только два теста из трёх
suite = unittest.TestSuite()
suite.addTest(TestMath("test_add"))
suite.addTest(TestMath("test_mul"))
result = unittest.TextTestRunner(verbosity=2).run(suite)
print("Тестов в наборе:", result.testsRun)
Вывод: (в набор попали только два выбранных теста)
Ran 2 tests in 0.000s OK Тестов в наборе: 2
На практике ручные наборы нужны редко — чаще полагаются на автообнаружение. Но знать механизм полезно: на нём строятся свои стратегии запуска (smoke-наборы, регрессионные прогоны).
Когда уместно пропускать, а когда — нет
Пропуск — инструмент честный, но опасный при злоупотреблении. Хороший повод для skip: тест зависит от условия, которого сейчас нет (нужная ОС, версия библиотеки, внешний сервис в интеграционных тестах). Плохой повод — «тест мешает, временно отключу». Такой пропуск с пометкой «временно» живёт годами, и поведение остаётся непроверенным. Если тест больше не нужен — удалите его осознанно; если нужен, но падает — чините, а не прячьте. skip всегда требует причины именно для того, чтобы вы её обдумали.
expectedFailure против skip
Эти два механизма решают разные задачи, и их легко перепутать. skip говорит «не запускай этот тест вовсе». expectedFailure — «запусти, я знаю, что он упадёт». Разница принципиальная: ожидаемо падающий тест выполняется, и если баг внезапно починят, unittest сообщит об «unexpected success». Это автоматическое напоминание убрать пометку. Пропущенный же тест молчит и ничего не отслеживает. Поэтому для известного, но временного бага лучше expectedFailure — он не даст забыть про проблему.
Итог
@skip,@skipIf,@skipUnless— пропускают тесты, оставляя их в отчёте.@expectedFailure— помечает известный баг; сборка остаётся зелёной.- Неожиданный успех ожидаемо-падающего теста — сигнал убрать пометку.
TestSuiteпозволяет собирать наборы тестов вручную.