unittest — Фреймворк тестирования юнитов

New in version 2.1.

(Если вы уже знакомы с основами концепции тестирования, то вы, возможно, захотите перейти сразу к список методов утверждений (assert methods).)

Фреймворк тестирования юнитов Python, иногда называемый “PyUnit”, является версией Python`а для JUnit от Kent Beck и Erich Gamma. JUnit, в свою очередь, является Java версией фреймворка тестирования от Kent’а для Smalltalk. Каждый из них является стандартом де факто для своего языка.

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

Для того, чтобы достичь этого, unittest поддерживает некоторые важные коцепции:

испытательный стенд
испытательный стенд (test fixture) представляет подготовку, необходимой, чтобы выполнить один или более тестов и все необходимые действия по отчистке. Это может включать, например, создание временных или проксирующих баз данных или запуск серверного процесса.
тестовый случай
тестовый случай (test case) - минимальный юнит тестирования. Он проверяет ответы для разных наборов данных. unittest предоставляет базовый класс TestCase, который можно использовать для создания новых тестовых случаев.
набор тестов
набор тестов (test suite) является набором тестовых случаев, наборов тестов или и того и другого. Он используется для объединения тестов, которые должны быть исполнены вместе.
исполнитель тестов
исполнитель тестов (test runner) является компонентом, который управляет выполнением тестов и представляет пользователю результат. Исполнитель может использовать графический или текстовый интерфейс или возвращать специальное значение, которое сообщает о результатах выполнения тестов.

Понятия тестового случая и испытательного стенда поддерживаются классами TestCase и FunctionTestCase; первый должен быть использован для создания новых тестов, а последний может быть использован для интеграции существующих тестов с фреймворком, основанном на unittest. При создании испытательного стенда при помощи TestCase, методы setUp() tearDown() могут быть переопределены для инициализации стенда и очистки после тестов. Вместе с FunctionTestCase, существующие функции могут быть переданы в конструктор для этих целей. Во время выполнения теста, сперва выполняется инициализация стенда, если она проходит успешно, метод очистки выполняется после выполнения каждого теста, вне зависимости от результата теста. Каждый экземпляр TestCase будет использоваться для запуска одного тестового метода, так что стенд создаётся для каждого теста.

Набор тестов реализуется классом TestSuite. Этот класс позволяет объединять отдельные тесты и наборы тестов; когда выполняется набор тестов, то выполняются все тесты добавленные в набор и в его дочерние наборы.

Выполнитель тестов - это объект, который предоставляет всего один метод, run(), который принимает объект TestCase или TestSuite в качестве параметра и возвращает результирующий объект. Класс TestResult используется как результирующий объект. unittest предоставляет класс TextTestRunner как пример выполнителя тестов, который по умолчанию выводит итог в стандартный поток ошибок. Альтернативные выполнители тестов могут быть реализованы и для других окружений (например, графических) без необходимости наследования из определённого класса.

See also

Module doctest
Другой модуль тестирования с совершенно другим подходом.

unittest2: Обратное портирование новых возможностей unittest для Python 2.4-2.6

В unittest для Python 2.7 было добавлено много новых возможностей, включая поиск тестов. unittest2 позволяет использовать эти возможности в более ранних версиях Python.
Simple Smalltalk Testing: With Patterns
статья Kent Beck’а про фреймворк для тестирования, использующий общий с unittest шаблон.
Nose и py.test
сторонний фреймворк тестирования, использующий лёгкий синтаксис для написания тестов. Например, assert func(10) == 42.
The Python Testing Tools Taxonomy
Расширяемый список инструментов для тестирования на Python, включая фреймворки для функционального тестирования и библиотеки mock-объектов.
Testing in Python Mailing List
Группа по интересам для обсуждения тестирования и инструментов для этого в Python.

Основные примеры

Модуль unittest предоставляет бокатый набор инструментов для создания и запуска тестов. Этот раздел демонстрирует, что небольшой набор этих инструментов удволетвоярет большинство ваших потребностей.

Вот короткий скрипт для тестирования трёх функций из модуля random:

import random
import unittest

class TestSequenceFunctions(unittest.TestCase):

    def setUp(self):
        self.seq = range(10)

    def test_shuffle(self):
        # проверяем, что перемешанная последовательность не потеряла
        # ни одного элемента
        random.shuffle(self.seq)
        self.seq.sort()
        self.assertEqual(self.seq, range(10))

        # возбуждает исключение для неизменяемых последовательностей
        self.assertRaises(TypeError, random.shuffle, (1,2,3))

    def test_choice(self):
        element = random.choice(self.seq)
        self.assertTrue(element in self.seq)

    def test_sample(self):
        with self.assertRaises(ValueError):
            random.sample(self.seq, 20)
        for element in random.sample(self.seq, 5):
            self.assertTrue(element in self.seq)

if __name__ == '__main__':
    unittest.main()

Набор тестов создаётся при помощи подкласса unittest.TestCase. Три отдельных теста определены в методах, чьи имена начинаются с test. Это соглашение об именах сообщает выполнителю тестов о том, какие методы содержат тесты.

Задачей каждого теста является вызов assertEqual() для проверки ожидаемого вывода; assertTrue() для проверки условий; или assertRaises() для проверки того, что) возбуждается ожидаемое исключение. Эти методы используются вместо выражения assert, так что выполнитель тестов может собирать все результаты тестов и создавать отчёт.

Когда определён метод setUp(), выполнитель тестов запустит этот метод перед каждым тестом. Похожим образом если определён метод tearDown(), выполнитель тестов будет вызывать этот метод после каждого теста. В нашем примере setUp() использовался для создания свежей последовательности для каждого теста.

Финальный блок показывает простой способ выполнить тесты. unittest.main() предоставляет интерфейс командной строки к тестовому скрипту. Когда он запускается из командной строки, скрипт из примера выше даст вывод вроде этого:

...
----------------------------------------------------------------------
Ran 3 tests in 0.000s

OK

Вместо unittest.main(), есть другие способы запуска тестов с более точным управлением, более подробным выводом, и для которых не обязательно использовать командную строку. Например, последние две строки можно заменить следующими детальным управление:

suite = unittest.TestLoader().loadTestsFromTestCase(TestSequenceFunctions)
unittest.TextTestRunner(verbosity=2).run(suite)

Запустив полученный скрипт в интерпретаторе или в другом скрипте, мы получим следующий вывод:

test_choice (__main__.TestSequenceFunctions) ... ok
test_sample (__main__.TestSequenceFunctions) ... ok
test_shuffle (__main__.TestSequenceFunctions) ... ok

----------------------------------------------------------------------
Ran 3 tests in 0.110s

OK

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

Интерфейс командной строки

Модуль unittest может быть использован из командной строки для запуска тестов из модулей, классов или даже отдельных методов:

python -m unittest test_module1 test_module2
python -m unittest test_module.TestClass
python -m unittest test_module.TestClass.test_method

Вы можете использовать список с любой комбинацией имён модулей и полных имён классов или методов.

Вы можете запускать тесты в более детальном режиме при помощи флага -v:

python -m unittest -v test_module

Для получения полного списка всех опций командной строки:

python -m unittest -h

Changed in version 2.7: В ранних версиях можно было запускать только отдельные методы, но не модули и классы.

Опции командной строки

unittest поддерживает следующие опции командной строки:

-b, --buffer

Потоки стандартного вывода и стандартного вывода ошибок буфферизуются во время выполнения тестов. Вывод во время прохождения тестов сбрасывается. Вывод обрабатывается нормально если тест не проходит или выдаёт ошибку и к нему добавляется сообщение об ошибке.

-c, --catch

Control-C во время выполнения теста ожидает завершения текущего теста и затем сообщает результаты на данный момент. Второе нажатие control-C вызывает обычное исключение KeyboardInterrupt.

Смотрите Обработка сигналов где описываются функции, которые предоставляют эту функциональность.

-f, --failfast

Завершает выполнение теста на первой ошибке.

New in version 2.7: Были добавлены опции командной строки -b, -c и -f.

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

Поиск тестов

New in version 2.7.

Unittest поддерживает простое обнаружение тестов. Для этого все модули импортируемы как модули или пакеты из каталога проекта верхнего уровня (то есть, имена их файлов должны быть корректными идентификаторами).

Поиск тестов реализован в TestLoader.discover(), но может быть использован и из командной строки. Пример использования:

cd project_directory
python -m unittest discover

Подкоманда discover имеет следующие опции:

-v, --verbose

Подробный вывод

-s, --start-directory directory

Каталог для начала поиска (по умолчанию .)

-p, --pattern pattern

Шаблон, которому должны соответствовать тестовые файлы (по умолчанию test*.py)

-t, --top-level-directory directory

Каталог верхнего уровня проека (по умолчанию - стартовый каталог)

Опции -s, -p, и -t могут быть переданы как позиционные аргументы в этом порядке. Следущие две строки эквивалентны:

python -m unittest discover -s project_directory -p '*_test.py'
python -m unittest discover project_directory '*_test.py'

Вместо пути можно передать имя пакета, например myproject.subpackage.test, вместо начального каталога. Имя пакета, которое вы указываете будет импортировано, а его расположение в файловой системе будет использовано как начальный каталог.

Caution

Обнаружение теста загружает тесты импортируя их. После того, как были найдены все тестовые файлы в стартовом каталоге, их пути преобразуются в имена пакетов для импорта. Например, foo/bar/baz.py будет импортирован как foo.bar.baz.

Если у вас есть глобально установленный пакет и вы пытаетесь обнаружить тесты в другой копии пакета, тогда импорт возможно произойдёт из неверного места. Если это происходит, обнаружитель тестов предупредит вас об этом и завершит работу.

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

Модули и пакеты тестов могут настроить загрузку и поиск тестов при помощи `протокола load_tests`_.

Организация тестового кода

Основные строительные блоки юнит-тестов — тестовый случай — одиночные сценарии, которые должны быть настроены и проверены на корректное выполнение. В unittest, тестовые случаи представлены экземплярами класса TestCase unittest‘а. Для того, чтобы сделать свой тестовый случай вы должны написать подкласс TestCase, или использовать FunctionTestCase.

Экземпляр класса-наследника от TestCase является объектом, который может запустить один тестовый метод вместе с опциональным кодом настройи и очистки.

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

Простейший подкласс TestCase просто переопределяет метод runTest() для того, чтобы выполнять конкретный код теста:

import unittest

class DefaultWidgetSizeTestCase(unittest.TestCase):
    def runTest(self):
        widget = Widget('The widget')
        self.assertEqual(widget.size(), (50, 50), 'incorrect default size')

Обратите внимание, что для того, чтобы протестировать что-то мы используем один из assert*() методов, предоставляемых базовым классом TestCase. Если тест не удаётся, будет возбуждено исключение, и unittest пометит этот тестовый случай как failure. Все другие исключения будут трактоваться как errors. Это поможет вам определить, в чём кроется проблема: failures возникает при некорректом результате - вы ожидали 6, а получили 5. Errors возникают из-за ошибок в коде, например, TypeError при некорректном вызове функции.

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

testCase = DefaultWidgetSizeTestCase()

Далее, таких тестовых случаем может быть несколько, а их настройка может быть одинаковой. В таком случае, создание Widget в каждом из 100 тестовых случаев для подклассов может означать ненужное дублирование.

К счастью, мы можем вынести настроечный код, реализовав метод setUp(), который автоматически вызывается фреймворком, когда мы запускаем тест:

import unittest

class SimpleWidgetTestCase(unittest.TestCase):
    def setUp(self):
        self.widget = Widget('The widget')

class DefaultWidgetSizeTestCase(SimpleWidgetTestCase):
    def runTest(self):
        self.assertEqual(self.widget.size(), (50,50),
                         'incorrect default size')

class WidgetResizeTestCase(SimpleWidgetTestCase):
    def runTest(self):
        self.widget.resize(100,150)
        self.assertEqual(self.widget.size(), (100,150),
                         'wrong size after resize')

Если метод setUp() возбуждает исключение во время выполнения теста, фреймворк предполагает, что тест содержит существенную ошибку и метод runTest() даже не будет запущен.

Похожим образом, мы можем предоставить метод tearDown(), который выполняется после метода runTest():

import unittest

class SimpleWidgetTestCase(unittest.TestCase):
    def setUp(self):
        self.widget = Widget('The widget')

    def tearDown(self):
        self.widget.dispose()
        self.widget = None

Если setUp() выполняется успешно, метод tearDown() будет выполнен вне зависимости от метода runTest().

Такое рабочее окружение для тестирования называется стендом.

Достаточно часто несколько маленьких тестов используют один и тот же стенд. В этом случае мы приходим к созданию большого числа маленьких однометодовых подклассов SimpleWidgetTestCase, таких как DefaultWidgetSizeTestCase. Это требует уйму времени и утомительно, так что в том же духе, что и JUnit, unittest предоставляет похожий механизм:

import unittest

class WidgetTestCase(unittest.TestCase):
    def setUp(self):
        self.widget = Widget('The widget')

    def tearDown(self):
        self.widget.dispose()
        self.widget = None

    def test_default_size(self):
        self.assertEqual(self.widget.size(), (50,50),
                         'incorrect default size')

    def test_resize(self):
        self.widget.resize(100,150)
        self.assertEqual(self.widget.size(), (100,150),
                         'wrong size after resize')

Тут мы не использовали метод runTest(), а вместо него релизовали два других тестовых метода. Экмзепляр класса теперь запустит каждый из test_*() методов, где self.widget будет создан и разрушен отдельно для каждого экземпляра. Когда мы создаём экземпляр, мы должны определить тестовый метод, который он будет выполнять. Мы делаем это передвая имя метода в конструктор:

defaultSizeTestCase = WidgetTestCase('test_default_size')
resizeTestCase = WidgetTestCase('test_resize')

Экземпляры тестового случая группируются вместе в соответствии с функционалом, который они тестирюут. unittest предоставляет для этого механизм: набор тестов, предоставленный классом TestSuite unittest‘а:

widgetTestSuite = unittest.TestSuite()
widgetTestSuite.addTest(WidgetTestCase('test_default_size'))
widgetTestSuite.addTest(WidgetTestCase('test_resize'))

Для того, чтобы проще запускать тесты, как мы увидим позже, хорошей идеей будет предоставить в каждом тестовом модуле вызываемый объект, который возвращает уже готовый набор тестов:

def suite():
    suite = unittest.TestSuite()
    suite.addTest(WidgetTestCase('test_default_size'))
    suite.addTest(WidgetTestCase('test_resize'))
    return suite

или даже:

def suite():
    tests = ['test_default_size', 'test_resize']

    return unittest.TestSuite(map(WidgetTestCase, tests))

Так как создание подкласса TestCase с многими похоже названными функциями широко распространено, unittest предоставляет класс TestLoader, который может быть использован для создания набора тестов и наполнения его тестами. Например:

suite = unittest.TestLoader().loadTestsFromTestCase(WidgetTestCase)

создаст набор тестов, который выполнит WidgetTestCase.test_default_size() и WidgetTestCase.test_resize. TestLoader использует префикс имени метода 'test' для идентификации тестовых методов.

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

Часто бывает желательно сгруппировать наборы тестов, чтобы запускать тесты для всей системы одновременно. Это легко сделать, так как экземпляры TestSuite могут быть добавлены в TestSuite, как и экземпляры TestCase:

suite1 = module1.TheTestSuite()
suite2 = module2.TheTestSuite()
alltests = unittest.TestSuite([suite1, suite2])

Вы можете расположить определения тестовых случаев и наборов тестов в том же модуле, что и код, который они тестируют (например, в файл widget.py), но есть преимущества в расположении теста в отдельном модуле, например в test_widget.py:

  • Тестовый модуль может быть запущен отдельно из командной строки.
  • Тестовый код легче отделить от поставляемого кода.
  • Гораздо меньше соблазна изменить тестовый код, чтобы он соответствовал тестируемому коду без весомой причины.
  • Тестовый код должен меняться гораздо реже, чем тестируемый.
  • Тестовый код можно проще подвергнуть рефакторингу.
  • Тесты для модулей, написаных на С, должны быть отделены от модулей, так почему бы не сделать так со всеми тестами?
  • Если стратегия тестирования изменяется, то нет нужды менять исходный код.

Повторное использование тестового кода

Некоторые пользователи могут обнаружить, что у них уже есть тестовый код, который они хотели бы запустить из под unittest, без того, чтобы преобразовывать все тестовые функции в подклассы TestCase.

По этой причине unittest предоставляет класс FunctionTestCase. Этот подкласс класса TestCase может быть использован как обёртка для существующих тестовых функций. Так же для него есть функции настройки и очистки.

Предположим, у нас есть следующая тестовая функция:

def testSomething():
    something = makeSomething()
    assert something.name is not None
    # ...

для которой можно создать эквивалентный экземпляр тестового случая:

testcase = unittest.FunctionTestCase(testSomething)

Если есть дополнительные методы настройки и очистки, которые должны быть вызваны как часть теста, то их тоже можно указать:

testcase = unittest.FunctionTestCase(testSomething,
                                     setUp=makeSomethingDB,
                                     tearDown=deleteSomethingDB)

Для того, чтобы облегчить миграцию существующих тестовых наборов, unittest позволяет тестам возбуждать AssertionError для обозначения падения теста. Однако, рекомендуется вместо этого явно использовать методы TestCase.fail*() и TestCase.assert*(), так как будущие версии unittest могут трактовать AssertionError по другому.

Note

Хотя FunctionTestCase может быть использован для быстрой конвертации существующих тестов в систему, основанную на unittest, делать так не рекомендуется. Затраченное время на создание соответствующего подкласса TestCase позволит вам позже проще проводить рефакторинг теста.

В некоторых случаях существующие тесты могут быть написаны при помощи модуля doctest. Этот модуль предоставляет класс DocTestSuite, который может автоматически создать экземпляр класса unittest.TestSuite из существующих тестов, основанных на doctest.

Игнорирование тестов и ожидаемые ошибки

New in version 2.7.

Unittest поддерживает игнорирование отдельных тестовых методов и даже целых тестовых классов. Кроме того, он поддерживает возможность пометить тест как “ожидающий ошибку”, что означает, что тест сломан и не будет пройден, но не должен учитываться как не пройденный экземпляром TestResult.

Пропуск теста делается просто использованием skip() decorator или одного из его условных вариантов.

Игнорирование в простом случае выглядит так:

class MyTestCase(unittest.TestCase):

    @unittest.skip("демонстрируем игнорирование")
    def test_nothing(self):
        self.fail("не произойдёт")

    @unittest.skipIf(mylib.__version__ < (1, 3),
                     "не поддерживается этой версией библиотеки")
    def test_format(self):
        # Тестирование работы только для определённой версии библиотеки.
        pass

    @unittest.skipUnless(sys.platform.startswith("win"),
                         "требуется Windows")
    def test_windows_support(self):
        # код тестирования под windows
        pass

Вот вывод этих примеров в “говорливом” режиме:

test_format (__main__.MyTestCase) ... skipped 'не поддерживается этой версией библиотеки'
test_nothing (__main__.MyTestCase) ... skipped 'демонстрируем игнорирование'
test_windows_support (__main__.MyTestCase) ... skipped 'требуется Windows'

----------------------------------------------------------------------
Ran 3 tests in 0.005s

OK (skipped=3)

Классы можно пропускать так же как и методы:

@unittest.skip("показываем пропуск классов")
class MySkippedTestCase(unittest.TestCase):
    def test_not_run(self):
        pass

TestCase.setUp() тоже может пропустить тесты. Это полезно в случае, если ресурсы, необходимые для настройки теста не доступны.

Ожидание ошибки обеспечивается при помощи декторатора expectedFailure():

class ExpectedFailureTestCase(unittest.TestCase):
    @unittest.expectedFailure
    def test_fail(self):
        self.assertEqual(1, 0, "broken")

Достаточно легко запустить свой собственный декоратор пропуска тестов, используя вызов skip() для тестов, которые вы хотите пропустить. Вот такой декоратор будет пропускать тесты, пока полученный объект не будет иметь определённый атрибут:

def skipUnlessHasattr(obj, attr):
    if hasattr(obj, attr):
        return lambda func: func
    return unittest.skip("{!r} doesn't have {!r}".format(obj, attr))

Следующие декораторы реализуют пропуск тестов и ожидание ошибок:

unittest.skip(reason)

Безусловно пропускает декорированный тест. reason должен описывать причину, почему тест был пропущен.

unittest.skipIf(condition, reason)

Пропускает декорированный тест, если condition истинно.

unittest.skipUnless(condition, reason)

Пропускает декорированный тест, пока condition не будет истинным.

unittest.expectedFailure()

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

exception unittest.SkipTest(reason)

Это исключение вызывается для пропуска теста.

Обычно вы можете использовать TestCase.skipTest() или один из декораторов вместо непосредственного вызова исключения.

Пропущенный тест не будет выполнять методы setUp() или tearDown(). Пропущенные классы не будут выполнять методы setUpClass() или tearDownClass().

Классы и функции

Этот раздел подробно описывает API модуля unittest.

Test cases

class unittest.TestCase(methodName='runTest')

Экземпляры класса TestCase представляют небольшие тестируемые кусочки из “вселенной” unittest. Этот класс должен быть использован как базовый класс, где конкретные тесты реализуются конкретными подклассами. Этот класс реализует интерфейсы, необходимые выполнителю тестов для выполнения тестов и методы, которые тестовый код может использовать для проверки и оповещения о различных ошибках.

Каждый экземпляр TestCase будет запускать один тестовый метод: метод и именем methodName. Если вы помните, у нас уже был пример чего-то вроде этого:

def suite():
    suite = unittest.TestSuite()
    suite.addTest(WidgetTestCase('test_default_size'))
    suite.addTest(WidgetTestCase('test_resize'))
    return suite

Тут мы создаём два экземпляра класса WidgetTestCase, каждый из которых запускает один тест.

methodName по умолчанию является runTest().

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

Методы в первой группе (запуск тестов):

setUp()

Метод вызывается для подготовки тестового стенда. Он вызывается непосредственно перед вызовом тестового метода; все исключения вызываемыми этим методом будут трактоваться как ошибки, а не как провал теста. По умолчанию ничего не делает.

tearDown()

Метод вызывается сразу после вызова тестового метода и сохранения результата. Он вызывается даже если тестовый метод вызвал исключение, так что его реализация в подклассе должна особенно внимательно относиться к проверке внутреннего состояния. Все исключения, вызванные этим методом будут трактоваться как ошибки, а не как провал теста. Этот метод вызывается только если setUp() завершился успешно, вне зависимости от результата тестового метода. Реализация по умолчанию не делает ничего.

setUpClass()

Метод класса выызваемый перед запуском тестов в классе. setUpClass вызывается только с одним аргументом - классом, и должен быть декорированным при помощи classmethod():

@classmethod
def setUpClass(cls):
    ...

Более подробно смотрите в Стенды класса и модуля .

New in version 2.7.

tearDownClass()

Метод класса, вызываемый после тестов в классе. tearDownClass вызывается только с одним аргументом - классом, и должен быть декорирован при помощи classmethod():

@classmethod
def tearDownClass(cls):
    ...

Более подробно смотрите в Стенды класса и модуля .

New in version 2.7.

run(result=None)

Запускает тест, собирает резльутат в объект результата теста, полученный через result. Если result не указан или равен None, создаётся временный объект результата (при помощи вызова метода defaultTestResult()), который затем и используется. Объект результата не возвращается вызвашему run().

Тот же самый эффект может быть достигнут простым вызовом экземпляра TestCase.

skipTest(reason)

Вызов этого метода в тестовом методе или в setUp() приведёт к пропуску теста. Более подробно смотрите в Игнорирование тестов и ожидаемые ошибки.

New in version 2.7.

debug()

Запуск теста без сбора результата. Это позволяет исключениям, которые вызываются тестом быть переданными вызывающему объекту и его можно использовать для поддержки запуска теста в режиме отладки.

Класс TestCase предоставляет некоторое количество методов для проверки и сообщения об ошибках, такие как:

Метод Проверяет что Начиная с
assertEqual(a, b) a == b  
assertNotEqual(a, b) a != b  
assertTrue(x) bool(x) is True  
assertFalse(x) bool(x) is False  
assertIs(a, b) a is b 2.7
assertIsNot(a, b) a is not b 2.7
assertIsNone(x) x is None 2.7
assertIsNotNone(x) x is not None 2.7
assertIn(a, b) a in b 2.7
assertNotIn(a, b) a not in b 2.7
assertIsInstance(a, b) isinstance(a, b) 2.7
assertNotIsInstance(a, b) not isinstance(a, b) 2.7

Все методы assert (кроме assertRaises(), assertRaisesRegexp()) принимают аргумент msg, который используется в качестве сообщения об ошибке при неудаче теста (смотри также longMessage).

assertEqual(first, second, msg=None)

Проверяет, что first и second равны. Елси они не равны - тест не пройден.

Кроме того, если first и second одного и того же типа и принадлежат list, tuple, dict, set, frozenset, unicode или любому другому типу, который является подклассом, зарегистрированным при помощи addTypeEqualityFunc(), будет вызвана специфичная для этого типа функция сравнения для того, чтобы получить более детальное сообщение об ошибке (смотрите также список методов специфичных для типов).

Changed in version 2.7: Добавлен автоматический вызов функций сравнения, специфичных для определённого типа.

assertNotEqual(first, second, msg=None)

Проверяет, что first и second не равны. Если значения равны, то тест считается проваленным.

assertTrue(expr, msg=None)
assertFalse(expr, msg=None)

Проверяет, что expr истинно (или ложно).

Обратите внимание, что это эквивалентно bool(expr) is True а не expr is True (для второго варианта используйте assertIs(expr, True)). Этот метод также не стоит использовать когда есть более конкретные методы (например, assertEqual(a, b) вместо assertTrue(a == b)), так как они обеспечивают лучшие сообщения об ошибках.

assertIs(first, second, msg=None)
assertIsNot(first, second, msg=None)

Проверяет, что first и second вычисляются (или не вычисляются) в тот же самый объект.

New in version 2.7.

assertIsNone(expr, msg=None)
assertIsNotNone(expr, msg=None)

Проверяет, что expr является (или нет) None.

New in version 2.7.

assertIn(first, second, msg=None)
assertNotIn(first, second, msg=None)

Проверяет, что first (не) находится в second.

New in version 2.7.

assertIsInstance(obj, cls, msg=None)
assertNotIsInstance(obj, cls, msg=None)

Проверяет, что obj (не) является экземпляром класса cls (который может быть классом или кортежем классов, как это поддерживается функцией isinstance()). Для того, чтобы проверить точное соответствие типу используйте assertIs(type(obj), cls).

New in version 2.7.

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

Метод Проверяет что Начиная с
assertRaises(exc, fun, *args, **kwds) fun(*args, **kwds) вызывает exc  
assertRaisesRegexp(exc, r, fun, *args, **kwds) fun(*args, **kwds) вызывает exc и сообщение соответствует regex r 2.7
assertRaises(exception, callable, *args, **kwds)
assertRaises(exception)

Проверяет, что при вызове callable с переданными позиционными или именованными аргументами вызовет исключение. Тест считается пройденным, если вызывается исключение exception, ошибкой будет считаться вызов другого исключения, а провалом теста - если исключение не вызвано. Для того, чтобы перехватить группу исключений, можно передать в качестве exception кортеж, который содержит эти исключения.

Если передан только аргумент exception, возвращается менеджер контекста, так что код для тестирования можно записать прямо в строку, вместо того, чтобы его оформлять в виде функции:

with self.assertRaises(SomeException):
    do_something()

Менеджер контекста сохраняет объект перехваченного исключения в своём атрибуте exception. Это может быть полезным, если мы хотим провести дополнительные проверки возбуждённого исключения:

with self.assertRaises(SomeException) as cm:
    do_something()

the_exception = cm.exception
self.assertEqual(the_exception.error_code, 3)

Changed in version 2.7: Добавлена возможность использовать assertRaises() как менеджер контекста.

assertRaisesRegexp(exception, regexp, callable, *args, **kwds)
assertRaisesRegexp(exception, regexp)

Похож на assertRaises(), но кроме этого проверяет, что regexp соответствует строковому представлению вызванного исключения. regexp может быть объектом регулярного выражения или строкой, содержащей регулярное выражение, которое можно использовать в re.search(). Например:

self.assertRaisesRegexp(ValueError, "invalid literal for.*XYZ'$",
                        int, 'XYZ')

или:

with self.assertRaisesRegexp(ValueError, 'literal'):
   int('XYZ')

New in version 2.7.

Есть и другие методы, которые используются для более специфических проверок, таких как:

Метод Проверяет что Начиная с
assertAlmostEqual(a, b) round(a-b, 7) == 0  
assertNotAlmostEqual(a, b) round(a-b, 7) != 0  
assertGreater(a, b) a > b 2.7
assertGreaterEqual(a, b) a >= b 2.7
assertLess(a, b) a < b 2.7
assertLessEqual(a, b) a <= b 2.7
assertRegexpMatches(s, r) r.search(s) 2.7
assertNotRegexpMatches(s, r) not r.search(s) 2.7
assertItemsEqual(a, b) sorted(a) == sorted(b) и работает с unhashable объектами 2.7
assertDictContainsSubset(a, b) все пары key/value из a присутствуют в b 2.7
assertAlmostEqual(first, second, places=7, msg=None, delta=None)
assertNotAlmostEqual(first, second, places=7, msg=None, delta=None)

Проверяет, что first и second приблизительно (или не приблизительно) равны, вычисляя разницу и округляя её до указанного в аргументе places знака после запятой (по умолчанию 7) и сравнивая эту разницу с 0. Обратите внимание, что этот метод округляет значение до заданного знака, а не до значимого знака (как функция round()).

Если указан аргумент delta вместо places, то разница между first и second должна быть меньше (или больше) или равна delta.

Указание и delta и places вызовет TypeError.

Changed in version 2.7: assertAlmostEqual() автоматически считает равные объекты почти равными. assertNotAlmostEqual() автоматически выдаёт ошибку, если объекты равны. Добавлен аргумент delta.

assertGreater(first, second, msg=None)
assertGreaterEqual(first, second, msg=None)
assertLess(first, second, msg=None)
assertLessEqual(first, second, msg=None)

Проверяет, что first соответственно >, >=, < или <= чем second, в зависимости от имени метода. Если нет, то тест не проходит:

>>> self.assertGreaterEqual(3, 4)
AssertionError: "3" unexpectedly not greater than or equal to "4"

New in version 2.7.

assertRegexpMatches(text, regexp, msg=None)

Проверяет, что regexp соответствует text. В случае не прохождения теста, сообщение об ошибке будет содержать шаблон и text (или шаблон и часть текста, которая внезапно совпала). regexp может быть объектом регулярного выражения или строкой, содержащей регулярное выражение, которую можно использовать для re.search().

New in version 2.7.

assertNotRegexpMatches(text, regexp, msg=None)

Проверяет, что поиск regexp не обрануживает соответствия в text. В случае не прохождения теста, сообщение об ошибке будет содержать шаблон и ту часть текста, которая совпала. regexp может быть объектом регулярного выражения или строкой, содержащей регулярное выражение, которую можно использовать для re.search().

New in version 2.7.

assertItemsEqual(actual, expected, msg=None)

Проверяет, что последовательность expected содержит те же элементы, что и actual, вне зависимости от их порядка. Если это не так, то будет выведено сообщение об ошибке, содержащее разницу между последовательностями.

Повторяющиеся элементы не игнорируются при сравнении actual и expected. Проверяется, что каждого элемента есть ровно такое же количество в каждой последовательности. Это эквивалент assertEqual(sorted(expected), sorted(actual)), но он так же работает с последовательностями нехешируемых объектов.

В Python 3 этот метод называется assertCountEqual.

New in version 2.7.

assertDictContainsSubset(expected, actual, msg=None)

Проверяет, что пары key/value в словаре actual являются надмножеством тех, что есть в expected. Иначе будет выведено сообщение об ошибке, содержащее отсутствующие ключи и не соответствующие значения.

New in version 2.7.

Deprecated since version 3.2.

Метод assertEqual() передаёт проверку равенства объектов одного типа различным типо-специфическим методам. Этим методы уже реализованы для для большей части встроенных типов, но можно зарегистрировать и свои методы при помощи addTypeEqualityFunc():

addTypeEqualityFunc(typeobj, function)

Регистрирует специфичный для типа метод, вызываемый assertEqual() для проверки того, что два объекта одного типа typeobj (не подклассы) равны. function должна принимать два позиционных аргумента и третий именованный msg=None, как и assertEqual(). Она должна вызывать self.failureException(msg) при обнаружении неравенства между первыми двумя параметрами – возможно предоставляя полезную информацию и объясняя детально причины неравенства в сообщении об ошибке.

New in version 2.7.

Список специфичных методов для типов, автоматически используемых assertEqual() приведён в следующей таблице. Обратите внимание, что обычно нет необходимости вызывать эти методы напрямую.

Метод Используется для сравнения Начиная с
assertMultiLineEqual(a, b) strings 2.7
assertSequenceEqual(a, b) sequences 2.7
assertListEqual(a, b) lists 2.7
assertTupleEqual(a, b) tuples 2.7
assertSetEqual(a, b) sets or frozensets 2.7
assertDictEqual(a, b) dicts 2.7
assertMultiLineEqual(first, second, msg=None)

Проверяет, что многострочная строка first равна строке second. Если они не равны, то разница между двумя строками будет включена в сообщение об ошибке. Этот метод используется по умолчанию при сравнении строк при помощи assertEqual().

New in version 2.7.

assertSequenceEqual(seq1, seq2, msg=None, seq_type=None)

Проверяет, что две последовательности равны. Если указан seq_type, то и seq1 и seq2 должны быть экземплярами seq_type или будет возбуждено исключение. Если последовательности отличаются, то будет выведено сообщение об ошибке, содержащее разницу между двумя последовательностями.

Этот метод не вызывается напрямую методом assertEqual(), но он используется для реализации assertListEqual() и assertTupleEqual().

New in version 2.7.

assertListEqual(list1, list2, msg=None)
assertTupleEqual(tuple1, tuple2, msg=None)

Проверяет, что два списка или корежа равны. В противном случае будет выдано сообщение об ошибке, содержащее разницу между двумя последовательностями. Ошибка так же появится в случае, если какой-либо параметр не того типа. Эти методы по умолчанию используются для сравнения списков и кортежей методом assertEqual().

New in version 2.7.

assertSetEqual(set1, set2, msg=None)

Проверяет, что два множества равны. Иначе будет показано сообщение об ошибке, которое содержит разницу между двумя множествами. Этот метод используется по по умолчанию для сравения двух множеств или frozenset assertEqual().

Тест не будет пройденным если set1 или set2 не имеет метода set.difference().

New in version 2.7.

assertDictEqual(expected, actual, msg=None)

Проверяет, что два словаря равны. В противном случае, сообщение об ошибке будет содержать разницу между словарями. Этот метод будет использован по умолчанию для сравнения словарей при вызове assertEqual().

New in version 2.7.

Наконец, TestCase предоставляет следующие методы и атрибуты:

fail(msg=None)

Сигнализирует о безусловном “падении” теста; в качестве сообщения об ошибке будет выведено msg или None.

failureException

Этот атрибут содержит исключение, вызываемое тестом. Если тестовый фреймворк должен использовать специализированные исключения, возможно, содержащие дополнительную информацию, то оно должно быть подклассом этого исключения, для того, чтобы “честно” играть с фреймворком. Значение по умолчанию - AssertionError.

longMessage

Если установлено в True, тогда все явные сообщения об ошибках, передаваемые в методы исключение будут добавлены к концу стандартного сообщения об ошибке. Стандартное сообщение об ошибке содержит полезную информацию об используемых объектах, например, сообщение от assertEqual покажет вам представление (repr) двух не равных объектов. Установка этого атрибута в True позволит Вам кроме этого сообщения добавить и какое-то своё.

По умолчанию этот атрибут равен False, что означает, что пользовательское сообщение, переданное методу исключения, затрёт стандартное сообщение.

Настройки класса могут быть переопределены в индивидуальных тестах, присваивая атрибуту экземпляра True или False перед вызовом методов исключения.

New in version 2.7.

maxDiff

Этот атрибут определяет максимальную длину разницы, выводимой методами исключения при не прохождении теста. По умолчанию он равен 80*8 символов. Методы исключения, на которые влияет этот атрибут - это assertSequenceEqual() (включая все последующие методы сравнения, которым метод делегирует свою работу), assertDictEqual() и assertMultiLineEqual().

Установка maxDiff в None означает, что нет ограничения по длине.

New in version 2.7.

Фреймворки для тестирования могут использовать следующие методы для сбора информации о тесте:

countTestCases()

Возвращает количество тестов, представленных этим тестовым объектом. Для экземпляров TestCase, это всегда будет 1.

defaultTestResult()

Возвращает экземпляр класса результата теста, который должен быть исопльзован для этого тестового случая (если других экземпляров результатов не предоставлено методу run()).

Для экземпляров TestCase он всегда будет экземпляром класса TestResult; подклассы TestCase должны переопределять его по необходимости.

id()

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

shortDescription()

Возвращает описание теста или None, если описания нет. Реализация этого метода по умолчанию возвращает первую строку из строк документации для метода, если она есть, или None.

addCleanup(function, *args, **kwargs)

Добавляет функцию, которая должна быть вызвана после tearDown() для уборки ресурсов, использованных в процессе тестирования. Функции будут вызываться в обратном порядке от их добавления (LIFO). Они вызываются с позиционными и именованными аргументами, переданными в addCleanup().

Если setUp() не срабатывает, то есть и tearDown() не вызывается, то все добавленные при помощи этого метода функции всё равно будут вызываны.

New in version 2.7.

doCleanups()

Этот мтеод вызывается в любом случае после tearDown(), или setUp(), если setUp() вызывал исключение.

Он отвечает за вызов всех отчищающих функций, добавленных методом addCleanup(). Если Вам нужно вызывать какие-то функции до tearDown(), тогда Вы должны вызвать метод doCleanups() сами.

doCleanups() вытаскивает (pop) методы из стека отчищающих функций по одной, так что она может быть вызвана в любое время.

New in version 2.7.

class unittest.FunctionTestCase(testFunc, setUp=None, tearDown=None, description=None)

Этот класс реализует часть интерфейса TestCase, который позволяет исполнителю тестов провести тест, но не предоставляет методов, которые тестовый код может использовать для проверки и сообщении об ошибках. Он используется для создания тестовых случаев при помощи “наследственного” тестового кода, позволяя интегрировать его в основанные на unittest тестирующие фреймворки.

Устаревшие псевдонимы

По историческим причинам, некоторые методы класса TestCase имеют один или более псевдонимов, которые на данный момент уже устарели. Следующая таблица перечисляет корректные имена вместе с их устаревшими псевдонимами:

Имя метода Устаревшие псевдонимы
assertEqual() failUnlessEqual, assertEquals
assertNotEqual() failIfEqual
assertTrue() failUnless, assert_
assertFalse() failIf
assertRaises() failUnlessRaises
assertAlmostEqual() failUnlessAlmostEqual
assertNotAlmostEqual() failIfAlmostEqual

Deprecated since version 2.7: псевдонимы, перечисленные во втором столбце

Группировка тестов

class unittest.TestSuite(tests=())

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

Если передан аргумент tests, то он должен быть итерируемым объектом, состоящим отдельных тестов или наборов тестов, которые будут использоваться для конструирования набора тестов. Кроме того, есть дополнительные методы, которые позволяют позже добавить тест или набор тестов.

Объекты TestSuite ведут себя подобно объектам TestCase, за исключением того, что они сами не реализуют тесты. Вместо этого, они используются для объединения тестов, которые должны быть запущенны одновременно, в группы. Вам доступно несколько методов для добавления тестов к TestSuite:

addTest(test)

Добавлет в набор TestCase или TestSuite.

addTests(tests)

Добавлет все тесты из итерируемых объектов TestCase и TestSuite в тестовый набор.

Это эквивалентно итерации по tests с вызовом addTest() для каждого элемента.

TestSuite имеет следующие общие методы с TestCase:

run(result)

Запускает тесты, ассоциированные с этим набором, собирая результат в объект результата тестов, переданный через аргумент result. Обратите внимание, что в отличие от TestCase.run(), TestSuite.run() требует передачи объекта результата тестов.

debug()

Запускает тесты, ассоциированные с этим набором, не собирая результат. Это позволяет исключениям, возбуждаемым тестами, доходить до вызывающего кода и его можно использовать для запуска тестов в отладчике.

countTestCases()

Возвращает количество тестов, представленных этим объектом, включая все тесты и вложенные наборы.

__iter__()

Тесты, собранные в TestSuite всегда доступны через итерации. Подклассы могут предоставлять тесты переопределив __iter__(). Обратите внимание, что этот метод может быть вызван несколько раз для одного набора (например, когда подсчитывается количество тестов или они сравниваются на идентичность), так что тесты, возвращаемые методом, должны быть одинаковы для все повторных итераций.

Changed in version 2.7: В ранних версиях TestSuite к тестам обращались на прямую, а не через итерации, так что переопределение __iter__() не было достаточным для доступа к тестам.

При типичном использовании объекта TestSuite, метод run() вызывается классом TestRunner, а не конечным пользователем теста.

Загрузка и выполнение тестов

class unittest.TestLoader

Класс TestLoader используется для создания набора тестов из классов и модулей. Обычно нет необходимости создавать экзмепляры этого класса; модуль unittest предоставляет экзмепляр, который можно использовать как unittest.defaultTestLoader. Тем не менее, использование подкласса или экземпляра позволит Вам настроить некоторые свойства.

Объекты TestLoader имеют следующие методы:

loadTestsFromTestCase(testCaseClass)

Возвращает набор из всех тестов, содержащихся в testCaseClass, полученном из TestCase.

loadTestsFromModule(module)

Возвращает набор из всех тестов, содержащихся в полученном модуле. Этот метод просматривает module в поисков классов, унаследованных от TestCase и создаёт экземпляр класса для каждого метода, определённого в классе.

Note

Хотя использование иерархии из наследников класса TestCase может быть нормой в общих “стендах” и вспомогательных функциях, определение тестовых методов на базе классов, которые не предназначены для прямого вызова не будет нормально работать с этим методом. Но это может быть полезным в случае других “стендов”, которые определены в подклассах.

Если модуль предоставляет функцию load_tests, то она будет вызвана для загрузки тестов. Это позволяет модулям настроить загрузку тестов. Это `load_tests protocol`_.

Changed in version 2.7: Добавлена поддержка load_tests.

loadTestsFromName(name, module=None)

Возвращает набор из всех тестов для объекта, определённого строкой.

Определитель name является именем в точечной нотации, которое может быть разрешено в модуль, класс тестового случая, тестовый метод в классе теста, экземпляр TestSuite или в вызываемый объект, который возвращает экземпляры TestCase или TestSuite. Эти проверки применяются в указанном тут порядке. То есть метод в возможном классе тестового случая будет рассматриваться как “тестовый метод в классе тестового случая”, а не как “вызываемый объект”.

Например, если у Вас есть модуль SampleTests, содержащий класс SampleTestCase, унаследованный от TestCase с тремя тестовыми методами (test_one(), test_two(), и test_three()), то определитель 'SampleTests.SampleTestCase', переданный этому методу вернёт набор, который будет запускать все эти три метода. Использование определителя 'SampleTests.SampleTestCase.test_two' вернёт набор тестов, в котором будет содержаться только один тест - метод test_two(). Определитель может ссылаться на модули и пакеты, которые не были импортированы; как “побочный эффект” они будут импортированы.

Этот метод опционально расширяет name относительно данного module.

loadTestsFromNames(names, module=None)
Похож на loadTestsFromName(), но принимает последовательность имён, а не
одно имя. Возвращает набор тестов, который поддерживает все тесты,

определённые для каждого имени.

getTestCaseNames(testCaseClass)

Возвращает отсортированную последовательность имён методов, найденных в testCaseClass, который должен быть подкласс от TestCase.

discover(start_dir, pattern='test*.py', top_level_dir=None)

Обнаруживает и возвращает все тестовые модули из определённого стартового каталога, проходясь и по всем подкаталогам. Будут загружены только те тестовые файлы, которые соответствуют pattern. (Используется соотвествие шаблону в стиле shell.) Будут загружены только те имена модулей, которые можно импортировать (то есть, которые являются корректными идентификаторами Python).

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

Если импорт модуля не удаётся, например, из-за синтаксической ошибки, тогда это будет записано как отдельная ошибка и поиск тестов будет продолжен.

Если имя тестового пакета (каталога с файлом __init__.py) соответсвует шаблону, тогда пакет будет проверен на наличие функции load_tests. Если эта функция существует, то она будет вызвана с аргументами loader, tests, pattern.

Если существует load_tests, тогда поиск тестов не проводит рекурсию по пакету, load_tests сама отвечает за загрузку всех тестов пакета.

Шаблон намеренно не хранится как атрибут загрузчика, так что пакеты могут искать тесты сами. top_level_dir хранится, так что load_tests не нуждается в передаче этого аргумента в loader.discover().

start_dir может быть точечным именем модуля или каталогом.

New in version 2.7.

Следующие атрибуты TestLoader могут быть настроены либо при помощи создания подкласса, либо настройкой экземпляра:

testMethodPrefix

Строка с префиксом имён методов, которые будут интерпретированны как тестовые методы. Значение по умолчанию - 'test'.

Это влияет на getTestCaseNames() и все методы loadTestsFrom*().

sortTestMethodsUsing

Функция, которая будет использована для сравнения имён методов во время сортировки в getTestCaseNames() и всех методах loadTestsFrom*(). Значение по умолчанию - встроенная функция cmp(); атрибуту может быть присвоено значение None, чтобы отменить сортировку.

suiteClass

Вызываемый объект, который создаёт набор тестов из списка тестов. Для итогового объекта не надо создавать никаких дополнительных методов (No methods on the resulting object are needed). Значение по умолчанию - класс TestSuite.

Влияет на все методы loadTestsFrom*().

class unittest.TestResult

Этот класс используется для компиляции информации о том, какие тесты прошли успешно, а какие - нет.

Объекты TestResult хранят результаты набора тестов. Классы TestCase и TestSuite следят за тем, чтобы результаты тестов были корректно записаны; авторы тестов не должны заботиться о сохранении их результатов.

Тестирующие фреймворки, построенные на основе unittest могут хотеть получить доступ к объекту TestResult, сгенерированному при запуске набора тестов для изменения вывода результатов; для этих целей метод TestRunner.run() возвращает экземпляр TestResult.

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

errors

Список, содержащий кортежи из 2-х элементов: экзмепляра TestCase и строки, содержащей отформатированную трассировку. Каждый кортеж представляет собой тест, который вызвал неожиданное исключение.

Changed in version 2.2: Содержит отформатированную трассировку, а не результат функции sys.exc_info().

failures

Список, содержащий кортежи из 2-х элементов: экзмепляра TestCase и строки, содержащей отформатированную трассировку. Каждый кортеж представляет собой тест, в котором произошла ошибка, вызванная методами TestCase.assert*().

Changed in version 2.2: Содержит отформатированную трассировку, а не результат функции sys.exc_info().

skipped

Список, содержащий кортежи из 2-х элементов: экзмепляра TestCase и строки, описывающей причину пропуска теста.

New in version 2.7.

expectedFailures

Список, содержащий кортежи из 2-х элементов: экзмепляра TestCase и строки, содержащей отформатированную трассировку. Каждый кортеж представляет собой ожидаемую ошибку теста.

unexpectedSuccesses

Список, содержащий экзмепляры TestCase, которые были помечены как ожидающие ошибки, но ошибки не произошло.

shouldStop

Установлено в True, если выполение теста должно быть остановлено методом stop().

testsRun

Общее количество выполненных на данный момент тестов.

buffer

Если установлен в true, то sys.stdout и sys.stderr будут буфферизованы между вызовами startTest() и stopTest(). Собранный вывод будет отправлен в реальный sys.stdout и sys.stderr если тест выдаст ошибку или неудачу. Любой вывод будет также добавлен к сообщению об ошибке/неудаче.

New in version 2.7.

failfast

Если установлен в true, stop() будет вызван для первой же ошибки / неудаче и выполнение тестов будет остановлено.

New in version 2.7.

wasSuccessful()

Возвращает True, если все тесты до сих пор были пройдены, в противном случае возвращает False.

stop()

Этот метод может быть вызван для того, чтобы сообщить о том, что выполнение текущего набора тестов должно быть прервано. Это достигается заданием значения True для атрибута shouldStop. Объекты TestRunner должны учитывать этот флаг и прекращать своё выполнение без запуска дополнительных тестов.

Например, эта возможность используется классом TextTestRunner для того, чтобы остановить выполнение тестов, когда пользователь прерывает выполнение тестов с клавиатуры. Интерактивные инструменты, предоставляющие реализацию TestRunner могут использовать этот метод схожим образом.

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

startTest(test)

Вызывается, перед тем, как тестовый случай test будет запущен.

stopTest(test)

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

startTestRun(test)

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

New in version 2.7.

stopTestRun(test)

Вызывается после выполнения всех тестов.

New in version 2.7.

addError(test, err)

Вызывается, когда тестовый случай test вызывает неожиданное исключение. err - это кортеж в форме, возвращаемой sys.exc_info(): (type, value, traceback).

Реализация по умолчанию добавляет кортеж (test, formatted_err) к атрибуту errors экзмемпляра, где formatted_err - это отформатировання трассировка из err.

addFailure(test, err)

Вызывается, когда тестовый случай test сообщает о неудаче. err - это кортеж в форме, возвращаемой sys.exc_info(): (type, value, traceback).

Реализация по умолчанию добавляет кортеж (test, formatted_err) к атрибуту failures экзмемпляра, где formatted_err - это отформатировання трассировка из err.

addSuccess(test)

Вызывается, когда тестовый случай test завершился удачно.

Реализация по умолчанию ничего не делает.

addSkip(test, reason)

Вызывается при пропуске тестового случая test. reason - это причина пропуска теста.

Реализация по умолчанию добавляет кортеж (test, reason) к атрибуту skipped экземпляра.

addExpectedFailure(test, err)

Вызывается, когда тестовый случай test завершается с ошибкой, но он был помечен декоратором expectedFailure().

Реализация по умолчанию добавляет кортеж (test, formatted_err) к атрибуту expectedFailures экземпляра, где formatted_err - это отформатированная трассировка из err.

addUnexpectedSuccess(test)

Вызывается когда тестовый случай test был помечен декоратором expectedFailure(), но выполнен успешно.

Реализация по умолчанию добавляет тест к атрибуту unexpectedSuccesses экземпляра.

class unittest.TextTestResult(stream, descriptions, verbosity)

Конкретная реализация TestResult, используемая классом TextTestRunner.

New in version 2.7: Этот класс раньше назывался _TextTestResult. Старое имя всё ещё существует как псевдоним, но не рекомендуется.

unittest.defaultTestLoader

Экземпляр класса TestLoader, который должен быть общим (intended to be shared). Если не требуется дополнительной настройки TestLoader, то этот экземпляр может быть использован несколько раз, вместо того, чтобы создавать новые экзмепляры.

class unittest.TextTestRunner(stream=sys.stderr, descriptions=True, verbosity=1)

Базовая реализация выполнителя тестов, которая выводит результаты на стандартный вывод ошибок. У неё всего несколько настраеваемых параметров, но она очень проста. Графиеские приложения, котоыре запускают тесты, должны предоставить альтернативную реализацию.

_makeResult()

Этот метод возвращает экземпляр TestResult, используемый методом run(). Он не предназначен для непосредственного вызова, но может быть переопределён в подклассах для предоставления собственного TestResult.

_makeResult() создаёт экземпляр из класса или вызываемого объекта, переданного в конструктор TextTestRunner как аргумент resultclass. По умолчанию это TextTestResult. Экзмепляр будет создан со следующими аргументами:

stream, descriptions, verbosity
unittest.main([module[, defaultTest[, argv[, testRunner[, testLoader[, exit[, verbosity[, failfast[, catchbreak[, buffer]]]]]]]]]])

Программа командной строки, которая загружает набор тестов из module и запускает их; в первую очередь это предназначено для удобства выполнения тестовых модулей. Самое простое использование этой функции - добавить следующие строки в конец скрипта с тестами:

if __name__ == '__main__':
    unittest.main()

Вы можете запустить тесты с более подробным выводом, передав аргумент verbosity:

if __name__ == '__main__':
    unittest.main(verbosity=2)

Аргумент defaultTest - это имя теста, который должен быть запущен, если имена тестов не переданы через argv. Если не определён или равен None и через argv не переданы имена тестов, то все тесты, найденные в module будут запущены.

Аргумент argv может быть списком аргументов, переданных программе, где первый аргумент - имя программы. Если он не определён или равен None, то используются значения sys.argv.

Аргумент testRunner может быть либо классом выполнителя тестов, либо уже созданным его экземпляром. По умолчанию main вызывает sys.exit() с кодом выхода, который обозначает успех или неудачу прошедших тестов.

Аргумент testLoader должен быть экземпляром класса TestLoader, и по умолчанию является defaultTestLoader.

main поддерживает вызов из интерактивного интерпретатора при помощи передачи аргумента exit=False. В таком случае результат будет выведен в стандартный вывод, без вызова sys.exit():

>>> from unittest import main
>>> main(module='test_module', exit=False)

Параметры failfast, catchbreak и buffer имеют то же самое значение, что и соответствующие опции командной строки.

Вызов main возвращает экземпляр класса TestProgram. Он хранит результаты вызова тестов в атрибуте result.

Changed in version 2.7: Были добавлены аргументы exit, verbosity, failfast, catchbreak и buffer.

Протокол load_tests

New in version 2.7.

Модули или пакеты могут настроить процесс зарузки своих тестов при обычном запуске тестов или при их обнаружении реализовав функцию load_tests.

Если тестовый модуль определяет load_tests, она будет вызвана методом TestLoader.loadTestsFromModule() со следующими аргументами:

load_tests(loader, standard_tests, None)

Функция должна возвращать TestSuite.

loader - экземпляр TestLoader, выполняющий загрузку. standard_tests - тесты, который будут загружены по умолчанию из модуля. Обычно тестовые модули лишь добавляют или убирают несколько тестов из стандартного набора тестов. Трети аргумент используется при загрузке пакетов в процессе обнаружения тестов.

Типичная функция load_tests, которая загружает тесты из определённого набора классов TestCase может выглядеть так:

test_cases = (TestCase1, TestCase2, TestCase3)

def load_tests(loader, tests, pattern):
    suite = TestSuite()
    for test_class in test_cases:
        tests = loader.loadTestsFromTestCase(test_class)
        suite.addTests(tests)
    return suite

Если начинается поиск тестов из командной строки или в результате вызова TestLoader.discover() с шаблоном, которому соответствует имя пакета, тогда файл пакета __init__.py будет проверен на наличие load_tests.

Note

Шаблон по умолчанию - 'test*.py'. Этому соответствуют все файлы Python, которые начинаются с 'test', но не соответствуют каталоги.

Шаблону вроде 'test*' будет соответствовать как пакеты, так и модули.

Если файл __init__.py пакета определяет load_tests, тогда эта функция будет вызвана и поиск в пакете дальше вестить не будет. Функция load_tests будет вызвана со следующими аргументами:

load_tests(loader, standard_tests, pattern)

Она должна вернуть TestSuite, представляющий все тесты из пакета. (standard_tests будет содержать только тесты, собранные из __init__.py.)

Поскольку шаблон передаётся в load_tests, пакет может спокойно продолжать (и потециально изменять) обнаружение тестов. ‘Ничего не делающая’ фукнция load_tests для пакета будет выгдяеть так:

def load_tests(loader, standard_tests, pattern):
    # каталог верхнего уровня кешируется в экзмепляре загрузчика
    this_dir = os.path.dirname(__file__)
    package_tests = loader.discover(start_dir=this_dir, pattern=pattern)
    standard_tests.addTests(package_tests)
    return standard_tests

Стенды класса и модуля

Стенды уровня класса и модуля реализованы в TestSuite. Когда тестовый набор встечает тест из нового класса, тогда вызывается метод tearDownClass() из предыдущего класса (если он есть), за которым вызывается метод setUpClass() из нового класса.

Аналогично, если тест из модуля, отличного от предыдущего теста, тогда вызывается метод tearDownModule из предыдущего модуля, а затем setUpModule из нового.

После того, как все тесты были выполнены, запускается последний метод tearDownClass и tearDownModule.

Обратите внимание, что общие стенды не очень хорошо работают с [потенциальными] возможностями, вроде распараллеливания тестов и нарушают изоляцию тестов. Поэтому они должны использоваться с осторожностью.

Упорядочивание тестов, создаваемых загрузчиком unittest`а заключается в группировке всех тестов из одного модуля и класса. Это приводит к тому, что setUpClass / setUpModule (и т.д.) вызываются всего один раз на класс или модуль. Если вы изменяете этот порядок, так что тесты из разных модулей и классов могут быть перемешаны друг с другом, то эти функции создания общих стендов могут вызываться несколько раз при одном запуске тестов.

Общие стенды не предназначены для работы с наборами тестов с нестандартным порядком тестов. BaseTestSuite всё ещё доступен для тех фреймворков, которые не поддерживают общие стенды.

Если в одной из функций по созданию общих тестов возникает исключение, то тест будет помечен как с ошибкой. Поскольку на этом этапе нет соответствующего объекта теста, будет создан объект _ErrorHolder (имеющий тот же самый интерфейс, что и TestCase) для отображения ошибки. Если Вы используете обычный выполнитель тестов, тогда эта деталь для Вас ничего не значит, но если Вы используете “авторский” фреймворк, это может на что-то повлиять.

setUpClass и tearDownClass

Они должны быть реализованы как методы класса:

import unittest

class Test(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls._connection = createExpensiveConnectionObject()

    @classmethod
    def tearDownClass(cls):
        cls._connection.destroy()

Вызывать эти методы Вы должны сами. Их реализация в TestCase пустая.

Если возникает исключение при выполнении setUpClass, тогда не запускаются тесты класса и метод tearDownClass. Пропускаемые классы тоже не выполняют setUpClass и tearDownClass. Если исключением является SkipTest, тогда класс сообщит о том, что он был пропущен, а не что в нём произошла ошибка.

setUpModule и tearDownModule

Они должны быть реализованы как функции:

def setUpModule():
    createConnection()

def tearDownModule():
    closeConnection()

Если возникает исключение при выполнении setUpModule, тогда не запускаются тесты модуля и метод tearDownModule. Если исключением является SkipTest, тогда модуль сообщит о том, что он был пропущен, а не что в нём произошла ошибка.

Обработка сигналов

Опции командной строки -c/--catch, как и параметр catchbreak функции unittest.main(), позволяет провести более дружественный перехват control-C в процессе выполнения тестов. В таком случае control-C позволит завершиться выполняемому тесту, после чего выполнение тестов будет прекращено и будет выведен результат о тех тестах, которые успели пройти. Повторное нажатие control-c вызовет KeyboardInterrupt как обычно.

Обработка сигнала control-c пытается сохранить совместимость с кодом тестов, которые устанавливают свои собственные обработчики signal.SIGINT. Если вызывается обработчик unittest, а не установленный обработчик signal.SIGINT, то есть он был заменён в тесте системным или ему была делигирована обработка сигнала, тогда вызывается стандартный обработчик. Это ожидаемое поведение для кода, который замещает установленный обработчик и передаёт обработку ему. Для конкретных тестов, которым надо отключить обработку ``unittest``ом control-c, можно использовать декоратор removeHandler().

‘’не понял, если честно, предыдущий абзац(‘’

Есть несколько функций для создателей фреймворков, чтобы активировать обработку control-c в тестовых фреймворках.

unittest.installHandler()

IУстанавлвает обработчик control-c. Когда получается сигнал signal.SIGINT (обычно в ответ на нажатие пользователем control-c), вызываются все зарегистрированные результаты метода stop().

New in version 2.7.

unittest.registerResult(result)

Регистрирует объект TestResult для обработки control-c. Регистрация результата сохраняет слабую ссылку на результат, так что это не предохраняет от уборки результата сборщиком мусора.

Регистрация объекта TestResult не имеет побочных эффектов, если обработка control-c не активированы, так что тестовые фреймворки могут без условий регистрировать все результаты, которые они создают, вне зависимости от того, активирована обработка или нет.

New in version 2.7.

unittest.removeResult(result)

Убирает зарегистрированный результат. После того, как результат удалён, тогда метод stop() уже не будет вызван для этого объекта в ответ на control-c.

New in version 2.7.

unittest.removeHandler(function=None)

При вызове без аргументов эта функция удаляет обработчик control-c, если он был установлен. Эта функция так же может быть использована как декоратор теста для временного удаления обработчика во время выполнения теста:

@unittest.removeHandler
def test_signal_handling(self):
    ...

New in version 2.7.