test — Пакет регрессионных тестов для Python
Примечание
Пакет test предназначен для внутреннего использования Python. Он документирован для пользы разработчиков ядра Python. Любое использование этого пакета за пределами стандартной библиотеки Python не рекомендуется, так как код, упомянутый здесь, может измениться или быть удален без предварительного уведомления между выпусками Python.
Пакет test содержит все регрессионные тесты для Python, а также модули test.support и test.regrtest. Модуль test.support используется для улучшения ваших тестов, в то время как test.regrtest управляет набором тестов.
Каждый модуль в пакете test, имя которого начинается с test_, является набором тестов для определенного модуля или функции. Все новые тесты должны быть написаны с использованием модуля unittest или doctest. Некоторые более старые тесты написаны с использованием «традиционного» стиля тестирования, который сравнивает вывод, выведенный в sys.stdout; этот стиль тестирования считается устаревшим.
См. также
26.8.1. Написание модульных тестов для пакета test
Предпочтительно, чтобы тесты, использующие модуль unittest, следовали нескольким рекомендациям. Одна из них — называть модуль тестов, начиная с test_ и заканчивая именем тестируемого модуля. Методы тестов в модуле тестов должны начинаться с test_ и заканчиваться описанием того, что тестирует метод. Это необходимо, чтобы драйвер тестов распознавал методы как методы тестов. Кроме того, не следует включать строку документации для метода. Для предоставления документации для методов тестов следует использовать комментарий (например, # Tests function returns only True or False). Это делается потому, что строки документации выводятся, если они существуют, и, следовательно, не указывается, какой тест выполняется.
Часто используется базовая шаблонная структура:
import unittest
from test import support
class MyTestCase1(unittest.TestCase):
# Only use setUp() and tearDown() if necessary
def setUp(self):
... code to execute in preparation for tests ...
def tearDown(self):
... code to execute to clean up after tests ...
def test_feature_one(self):
# Test feature one.
... testing code ...
def test_feature_two(self):
# Test feature two.
... testing code ...
... more test methods ...
class MyTestCase2(unittest.TestCase):
... same structure as MyTestCase1 ...
... more test classes ...
if __name__ == '__main__':
unittest.main()
Этот шаблон кода позволяет запускать набор тестов test.regrtest, самостоятельно как сценарий, поддерживающий unittest CLI, или через python -m unittest CLI.
Цель регрессионного тестирования — попытаться сломать код. Это приводит к нескольким рекомендациям:
- Набор тестов должен проверять все классы, функции и константы. Это включает не только внешний API, который должен быть представлен внешнему миру, но также и «приватный» код.
- Предпочтителен белый ящик (исследование кода, тестируемого при написании тестов). Черный ящик (тестирование только опубликованного пользовательского интерфейса) недостаточно для проверки всех граничных и крайних случаев.
- Убедитесь, что протестированы все возможные значения, включая недопустимые. Это гарантирует, что не только все допустимые значения приемлемы, но и что ненадлежащие значения обрабатываются правильно.
- Исследуйте как можно больше путей кода. Проверьте, где происходит ветвление, и настройте входные данные, чтобы убедиться, что пройдено как можно больше различных путей по коду.
- Добавьте явный тест на любые обнаруженные ошибки для тестируемого кода. Это гарантирует, что ошибка не появится снова, если код будет изменен в будущем.
- Убедитесь, что вы очищаете после своих тестов (например, закрываете и удаляете все временные файлы).
- Если тест зависит от определенного состояния операционной системы, проверьте, что состояние уже существует, прежде чем пытаться выполнить тест.
- Импортируйте как можно меньше модулей и делайте это как можно раньше. Это сводит к минимуму внешние зависимости тестов и также сводит к минимуму возможное аномальное поведение из-за побочных эффектов импорта модуля.
-
Постарайтесь максимизировать повторное использование кода. В некоторых случаях тесты будут отличаться лишь небольшими деталями, такими как тип используемых входных данных. Минимизируйте дублирование кода, наследовавшись от базового класса тестов с классом, определяющим входные данные:
class TestFuncAcceptsSequencesMixin: func = mySuperWhammyFunction def test_func(self): self.func(self.arg) class AcceptLists(TestFuncAcceptsSequencesMixin, unittest.TestCase): arg = [1, 2, 3] class AcceptStrings(TestFuncAcceptsSequencesMixin, unittest.TestCase): arg = 'abc' class AcceptTuples(TestFuncAcceptsSequencesMixin, unittest.TestCase): arg = (1, 2, 3)При использовании этого шаблона помните, что все классы, которые наследуются от
unittest.TestCase, выполняются как тесты. КлассMixinв приведенном выше примере не содержит данных и поэтому не может выполняться сам по себе, поэтому он не наследуется отunittest.TestCase.
См. также
- Разработка, управляемая тестированием
-
Книга Кента Бека о написании тестов перед кодом.
26.8.2. Запуск тестов с помощью интерфейса командной строки
Пакет test может быть запущен как сценарий для управления набором регрессионных тестов Python благодаря параметру -m: python -m test. Внутри он использует test.regrtest; вызов python -m test.regrtest, используемый в предыдущих версиях Python, по-прежнему работает. Запуск сценария самостоятельно автоматически запускает все регрессионные тесты в пакете test. Он делает это, находя все модули в пакете, имена которых начинаются с test_, импортируя их и выполняя функцию test_main() при наличии или загружая тесты через unittest.TestLoader.loadTestsFromModule, если test_main не существует. Имена тестов для выполнения также могут быть переданы в сценарий. Указание одного регрессионного теста (python -m test test_spam) минимизирует вывод и выводит только то, прошел ли тест или нет.
Запуск test напрямую позволяет задавать ресурсы, доступные для тестов. Для этого используется параметр командной строки -u. Указание all в качестве значения для параметра -u включает все возможные ресурсы: python -m test -uall. Если требуются все ресурсы, кроме одного (более распространенный случай), можно перечислить отделённый запятыми список ресурсов, которые не требуются после all. Команда python -m test -uall,-audio,-largefile запустит test со всеми ресурсами, кроме ресурсов audio и largefile. Для получения списка всех ресурсов и других параметров командной строки выполните python -m test -h.
Некоторые другие способы выполнения регрессионных тестов зависят от платформы, на которой выполняются тесты. В Unix можно выполнить make test в каталоге верхнего уровня, где был построен Python. В Windows запуск rt.bat из каталога PCBuild запустит все регрессионные тесты.
test.support — Утилиты для набора тестов Python
Модуль test.support предоставляет поддержку набора регрессионных тестов Python.
Примечание
test.support не является общедоступным модулем. Он документирован здесь для помощи разработчикам Python в написании тестов. API этого модуля может быть изменён без обратной совместимости между выпусками.
В этом модуле определены следующие исключения:
-
exception test.support.TestFailed -
Исключение, которое должно быть поднято при ошибке теста. Это устарело в пользу тестов на основе
unittestи методов утвержденияunittest.TestCase.
-
exception test.support.ResourceDenied -
Подкласс
unittest.SkipTest. Вызывается, когда ресурс (например, сетевое соединение) недоступен. Вызывается функциейrequires().
В модуле test.support определены следующие константы:
-
test.support.verbose -
Trueпри включённом подробном выводе. Должен проверяться, когда требуется более подробная информация о проходящем тесте. verbose устанавливаетсяtest.regrtest.
-
test.support.is_jython -
Trueесли интерпретатор Jython.
-
test.support.TESTFN -
Устанавливается в имя, которое безопасно использовать в качестве имени временного файла. Любой созданный временный файл должен быть закрыт и удалён.
Модуль test.support определяет следующие функции:
-
test.support.forget(module_name) -
Удалить модуль с именем module_name из
sys.modulesи удалить все скомпилированные байт-файлы модуля.
-
test.support.is_resource_enabled(resource) -
Возвращает
Trueесли resource включен и доступен. Список доступных ресурсов устанавливается только приtest.regrtestвыполнении тестов.
-
test.support.requires(resource, msg=None) -
Вызывает
ResourceDeniedесли resource недоступен. msg — аргумент дляResourceDenied, если он вызван. Всегда возвращаетTrueпри вызове функцией,__name__которой'__main__'. Используется, когда тесты выполняютсяtest.regrtest.
-
test.support.findfile(filename, subdir=None) -
Возвращает путь к файлу с именем filename. Если соответствие не найдено, возвращается filename. Это не означает ошибку, так как это может быть путь к файлу.
Установка subdir указывает относительный путь для поиска файла, а не прямой поиск в каталогах пути.
-
test.support.run_unittest(*classes) -
Выполняет подклассы
unittest.TestCase, переданные в функцию. Функция сканирует классы на методы, начинающиеся с префиксаtest_и выполняет тесты индивидуально.Также можно передавать строки в качестве параметров; они должны быть ключами в
sys.modules. Каждый связанный модуль будет просканированunittest.TestLoader.loadTestsFromModule(). Это обычно встречается в следующейtest_main()функции:def test_main(): support.run_unittest(__name__)Это запустит все тесты, определенные в указанном модуле.
-
test.support.run_doctest(module, verbosity=None) -
Выполняет
doctest.testmod()для данного module. Возвращает(failure_count, test_count).Если verbosity —
None,doctest.testmod()выполняется с уровнем подробности, установленным вverbose. В противном случае — с уровнем подробностиNone.
-
test.support.check_warnings(*filters, quiet=True) -
Удобная обёртка для
warnings.catch_warnings(), которая упрощает проверку правильного подъёма предупреждения. Примерно эквивалентно вызовуwarnings.catch_warnings(record=True)сwarnings.simplefilter(), установленным вalwaysи с возможностью автоматической проверки записанных результатов.check_warningsпринимает 2-кортежи вида("message regexp", WarningCategory)в качестве позиционных аргументов. Если указаны один или несколько filters, или если необязательный ключевой аргумент quiet —False, проверяются ожидаемые предупреждения: каждый указанный фильтр должен соответствовать по крайней мере одному из предупреждений, поднятых закрытым кодом или тестом, в противном случае тест завершится неудачей; если какие-либо предупреждения подняты, но не соответствуют ни одному из указанных фильтров, тест завершится неудачей. Для отключения первой из этих проверок установите quiet вTrue.Если аргументов нет, используется значение по умолчанию:
check_warnings(("", Warning), quiet=True)В этом случае все предупреждения перехватываются, и не возникает никаких ошибок.
При входе в контекстный менеджер возвращается экземпляр
WarningRecorder. Внутренний список предупреждений изcatch_warnings()доступен через атрибут recorder объекта. Для удобства атрибуты объекта, представляющего последнее предупреждение, также доступны непосредственно через объект recorder (см. пример ниже). Если предупреждение не было поднято, то любой из атрибутов, которые в противном случае ожидались бы в объекте, представляющем предупреждение, вернётNone.Объект recorder также имеет метод
reset(), который очищает список предупреждений.Контекстный менеджер предназначен для использования следующим образом:
with check_warnings(("assertion is always true", SyntaxWarning), ("", UserWarning)): exec('assert(False, "Hey!")') warnings.warn(UserWarning("Hide me!"))В этом случае, если ни одно из предупреждений не было поднято, или было поднято другое предупреждение,
check_warnings()вызовет ошибку.Когда тесту требуется более глубокий анализ предупреждений, а не просто проверка их возникновения, можно использовать код такого типа:
with check_warnings(quiet=True) as w: warnings.warn("foo") assert str(w.args[0]) == "foo" warnings.warn("bar") assert str(w.args[0]) == "bar" assert str(w.warnings[0].args[0]) == "foo" assert str(w.warnings[1].args[0]) == "bar" w.reset() assert len(w.warnings) == 0В этом случае все предупреждения будут перехвачены, и код теста напрямую проверит перехваченные предупреждения.
Изменено в версии 3.2: Новые необязательные аргументы filters и quiet.
-
test.support.captured_stdin() -
test.support.captured_stdout() -
test.support.captured_stderr() -
Контекстные менеджеры, временно заменяющие указанный поток объектом
io.StringIO.Пример использования с потоками вывода:
with captured_stdout() as stdout, captured_stderr() as stderr: print("hello") print("error", file=sys.stderr) assert stdout.getvalue() == "hello\n" assert stderr.getvalue() == "error\n"Пример использования с потоком ввода:
with captured_stdin() as stdin: stdin.write('hello\n') stdin.seek(0) # call test code that consumes from sys.stdin captured = input() self.assertEqual(captured, "hello")
-
test.support.temp_dir(path=None, quiet=False) -
Контекстный менеджер, который создаёт временную директорию в path и возвращает директорию.
Если path —
None, временная директория создаётся с помощьюtempfile.mkdtemp(). Если quiet —False, менеджер контекста вызывает исключение при ошибке. В противном случае, если path указан и не может быть создан, выводится только предупреждение.
-
test.support.change_cwd(path, quiet=False) -
Контекстный менеджер, который временно меняет текущую рабочую директорию на path и возвращает директорию.
Если quiet —
False, менеджер контекста вызывает исключение при ошибке. В противном случае, он выводит только предупреждение и сохраняет текущую рабочую директорию.
-
test.support.temp_cwd(name='tempcwd', quiet=False) -
Контекстный менеджер, который временно создаёт новую директорию и меняет текущую рабочую директорию (CWD).
Менеджер контекста создаёт временную директорию в текущей директории с именем name перед временным изменением текущей рабочей директории. Если name —
None, временная директория создаётся с помощьюtempfile.mkdtemp().Если quiet —
Falseи невозможно создать или изменить CWD, генерируется ошибка. В противном случае генерируется только предупреждение, и используется исходная CWD.
-
test.support.temp_umask(umask) -
Контекстный менеджер, который временно устанавливает umask процесса.
-
test.support.can_symlink() -
Возвращает
Trueесли ОС поддерживает символические ссылки,Falseв противном случае.
-
@test.support.skip_unless_symlink -
Декоратор для запуска тестов, требующих поддержки символических ссылок.
-
@test.support.anticipate_failure(condition) -
Декоратор для условной маркировки тестов с
unittest.expectedFailure(). Любое использование этого декоратора должно сопровождаться комментарием, идентифицирующим соответствующую проблему отслеживания.
-
@test.support.run_with_locale(catstr, *locales) -
Декоратор для выполнения функции в другом локали, правильно сбрасывая его после завершения. catstr — категория локали в виде строки (например
"LC_ALL"). Передаваемые locales будут пробоваться последовательно, и первое допустимое локали будет использовано.
-
test.support.make_bad_fd() -
Создаёт недопустимый дескриптор файла, открывая и закрывая временный файл и возвращая его дескриптор.
-
test.support.import_module(name, deprecated=False) -
Эта функция импортирует и возвращает указанный модуль. В отличие от обычного импорта, эта функция вызывает
unittest.SkipTestесли модуль не может быть импортирован.Сообщения об устаревании модулей и пакетов подавляются во время этого импорта, если deprecated —
True.Добавлен в версии 3.1.
-
test.support.import_fresh_module(name, fresh=(), blocked=(), deprecated=False) -
Эта функция импортирует и возвращает свежую копию указанного модуля Python, удалив указанный модуль из
sys.modulesперед импортом. Обратите внимание, что в отличие отreload(), исходный модуль не затрагивается этой операцией.fresh — это итерируемый объект дополнительных имён модулей, которые также удаляются из кэша
sys.modulesперед импортом.blocked — это итерируемый объект имён модулей, которые заменяются на
Noneв кэше модулей во время импорта, чтобы гарантировать, что попытки импортировать их вызовутImportError.Указанный модуль и любые модули, указанные в параметрах fresh и blocked, сохраняются перед началом импорта, а затем повторно вставляются в
sys.modulesпо завершении свежей импортированной копии.Сообщения о устаревании модулей и пакетов подавляются во время этого импорта, если deprecated —
True.Эта функция вызовет
ImportError, если указанный модуль не может быть импортирован.Пример использования:
# Get copies of the warnings module for testing without affecting the # version being used by the rest of the test suite. One copy uses the # C implementation, the other is forced to use the pure Python fallback # implementation py_warnings = import_fresh_module('warnings', blocked=['_warnings']) c_warnings = import_fresh_module('warnings', fresh=['_warnings'])Добавлена в версии 3.1.
-
test.support.bind_port(sock, host=HOST) -
Связывает сокет с свободным портом и возвращает номер порта. Использует временные порты, чтобы убедиться, что мы используем несвязанный порт. Это важно, так как многие тесты могут выполняться одновременно, особенно в среде buildbot. Этот метод вызывает исключение, если
sock.familyравенAF_INET, аsock.typeравенSOCK_STREAM, и на сокете установленыSO_REUSEADDRилиSO_REUSEPORT. Тесты никогда не должны устанавливать эти параметры сокета для TCP/IP-сокетов. Единственный случай установки этих параметров — тестирование многоадресной рассылки через несколько UDP-сокетов.Кроме того, если параметр сокета
SO_EXCLUSIVEADDRUSEдоступен (например, в Windows), он будет установлен на сокете. Это предотвратит возможность связывания с нашим хостом/портом для других во время выполнения теста.
-
test.support.find_unused_port(family=socket.AF_INET, socktype=socket.SOCK_STREAM) -
Возвращает неиспользуемый порт, который должен быть подходящим для связывания. Это достигается путём создания временного сокета с той же семейной и типом, что и
sockпараметр (по умолчаниюAF_INET,SOCK_STREAM), и связыванием его со указанным адресом хоста (по умолчанию0.0.0.0) с портом, установленным на 0, для получения неиспользуемого временного порта от ОС. Временный сокет затем закрывается и удаляется, и возвращается временный порт.Для любых тестов, где серверный сокет должен быть привязан к определённому порту на время выполнения теста, следует использовать либо этот метод, либо
bind_port(). Какой из них использовать, зависит от того, создаёт ли вызывающий код сокет Python, или требуется указать неиспользуемый порт в конструкторе или передать его внешней программе (т.е. аргумент-acceptв режиме s_server openssl). Всегда отдавайте предпочтениеbind_port()передfind_unused_port(), когда это возможно. Использование жёстко заданного порта не рекомендуется, так как это может затруднить одновременное выполнение нескольких экземпляров теста, что представляет проблему для buildbot.
-
test.support.load_package_tests(pkg_dir, loader, standard_tests, pattern) -
Общая реализация протокола
load_testsмодуляunittestдля использования в тестовых пакетах. pkg_dir — это корневой каталог пакета; loader, standard_tests и pattern — это ожидаемые аргументы дляload_tests. В простых случаях,__init__.pyтестового пакета может быть следующим:import os from test.support import load_package_tests def load_tests(*args): return load_package_tests(os.path.dirname(__file__), *args)
-
test.support.detect_api_mismatch(ref_api, other_api, *, ignore=()) -
Возвращает множество атрибутов, функций или методов ref_api, которых нет в other_api, за исключением определённого списка элементов, которые необходимо игнорировать в этой проверке, указанного в ignore.
По умолчанию это пропускает приватные атрибуты, начинающиеся с «_», но включает все магические методы, т.е. те, которые начинаются и заканчиваются «__».
Добавлена в версии 3.5.
-
test.support.check__all__(test_case, module, name_of_module=None, extra=(), blacklist=()) -
Проверяет, что переменная
__all__модуля module содержит все имена общедоступных элементов.Имена общедоступных элементов (API) модуля автоматически определяются на основе соответствия соглашениям о именах общедоступных элементов и были определены в module.
Аргумент name_of_module может указывать (в виде строки или кортежа), в каких модулях мог быть определён API для его обнаружения как общедоступного API. Один из случаев этого — когда module импортирует часть своего общедоступного API из других модулей, возможно, из C-бекенда (например,
csvи его_csv).Аргумент extra может содержать набор имён, которые в противном случае не были бы автоматически обнаружены как «общедоступные», например объекты без атрибута
__module__. Если он предоставлен, он будет добавлен к автоматически обнаруженным.Аргумент blacklist может быть набором имён, которые не должны рассматриваться как часть общедоступного API, даже если их имена указывают на это.
Пример использования:
import bar import foo import unittest from test import support class MiscTestCase(unittest.TestCase): def test__all__(self): support.check__all__(self, foo) class OtherTestCase(unittest.TestCase): def test__all__(self): extra = {'BAR_CONST', 'FOO_CONST'} blacklist = {'baz'} # Undocumented name. # bar imports part of its API from _bar. support.check__all__(self, bar, ('bar', '_bar'), extra=extra, blacklist=blacklist)Добавлена в версии 3.6.
Модуль test.support определяет следующие классы:
-
class test.support.TransientResource(exc, **kwargs) -
Экземпляры — это менеджеры контекста, которые вызывают
ResourceDenied, если возникает указанный тип исключения. Любые аргументы ключевых слов обрабатываются как пары атрибут/значение, которые необходимо сравнить с любым исключением, поднятым в блокеwith. Только если все пары правильно соответствуют атрибутам исключения, поднимаетсяResourceDenied.
-
class test.support.EnvironmentVarGuard -
Класс, используемый для временного изменения или удаления переменных среды. Экземпляры могут использоваться как менеджеры контекста и имеют полную структуру словаря для запроса/изменения базовых
os.environ. После выхода из менеджера контекста все изменения переменных среды, сделанные через этот экземпляр, будут отменены.Изменено в версии 3.1: Добавлен интерфейс словаря.
-
EnvironmentVarGuard.set(envvar, value) -
Временно устанавливает переменную среды
envvarв значениеvalue.
-
EnvironmentVarGuard.unset(envvar) -
Временно удаляет переменную среды
envvar.
-
class test.support.SuppressCrashReport -
Менеджер контекста, используемый для попытки предотвратить всплытие диалоговых окон с ошибками при тестах, которые должны привести к сбою подпроцесса.
В Windows он отключает диалоговые окна Windows Error Reporting с помощью SetErrorMode.
В UNIX используется
resource.setrlimit()для установки мягкого ограниченияresource.RLIMIT_COREв 0 для предотвращения создания файла coredump.На обеих платформах старое значение восстанавливается методом
__exit__().
-
class test.support.WarningsRecorder -
Класс, используемый для записи предупреждений для юнит-тестов. Дополнительные сведения см. в документации к
check_warnings()выше.
-
class test.support.FakePath(path) -
Простой объект пути. Он реализует метод
__fspath__()который просто возвращает аргумент path. Если path является исключением, оно будет поднято в__fspath__().
© 2001–2020 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.6/library/test.html