Python/Справочник по библиотеке Python 2.6: различия между версиями

Содержимое удалено Содержимое добавлено
орфография, пунктуация
м <source> -> <syntaxhighlight> (phab:T237267)
Строка 20:
 
Возвращает '''True''' если все значения последовательности правдивые (или последовательность пуста). Эквивалентно:
<sourcesyntaxhighlight lang="python">
def all(iterable):
for element in iterable:
Строка 26:
return False
return True
</syntaxhighlight>
</source>
''Появилось в версии 2.5''
 
Строка 33:
Возвращает '''True''' если хоть один из элементов правдив. Если последовательность пуста возврощает False. Эквивалентно:
 
<sourcesyntaxhighlight lang="python">
def any(iterable):
for element in iterable:
Строка 39:
return True
return False
</syntaxhighlight>
</source>
 
''Появилось в версии 2.5''
Строка 81:
 
Класс-метод получает класс с неявным первым аргументом, например метод получает экземпляр объекта. Декларация класса-метода такова:
<sourcesyntaxhighlight lang="python">
class C:
@classmethod
def f(cls, arg1, arg2, ...): ...
</syntaxhighlight>
</source>
@classmethod это функция-декоратор
 
Строка 152:
Вот короткий сценарий для тестирования трех функций из модуля '''random''':
 
<sourcesyntaxhighlight lang="python">
import random
import unittest
Строка 178:
if __name__ == '__main__':
unittest.main()
</syntaxhighlight>
</source>
 
Тестовый вариант создан как подкласс '''unittest.TestCase'''. Три отдельных теста заданы с помощью методов, названия которых начинаются с последовательности 'test'. Такое соглашение об наименовании сообщает исполнитель тестов о том, какие методы представляют тесты.
Строка 195:
 
Существуют и другие способы выполнение тестов, кроме '''unittest.main()''', причем с большей степенью контроля, не таким скупым выводом и не обязательно запускаемые из командной строки. Например, последние две строки могут быть заменены следующими:
<sourcesyntaxhighlight lang="python">
suite = unittest.TestLoader().loadTestsFromTestCase(TestSequenceFunctions)
unittest.TextTestRunner(verbosity=2).run(suite)
</syntaxhighlight>
</source>
 
Результатом выполнения измененного сценария из интерпретатора, либо из другого сценария, будет следующий вывод:
Строка 222:
Простейший подкласс '''TestCase''' просто замещает метод '''runTest()''' для выполнения определенного тестового кода:
 
<sourcesyntaxhighlight lang="python">
import unittest
 
Строка 229:
widget = Widget('The widget')
self.assertEqual(widget.size(), (50, 50), 'incorrect default size')
</syntaxhighlight>
</source>
 
Обратите внимание, что для того чтобы протестировать что-либо, используется один из методов '''assert*()''' или '''fail*()''' базового класса '''TestCase()'''. Если тест проваливается, поднимается исключение, и '''unittest''' идентифицирует тестовый вариант как «провалившийся» (failure). Любые иные исключения воспринимаются как ошибки (errors). Такое разделение позволяет определить место проблемы: ''failure'' вызываются неправильными результатами – 5 в том месте, в котором ожидается 6. ''Errors'' вызываются некорректным кодом – например, причиной'''TypeError''' является неправильный вызов функции
Строка 235:
Способ выполнения тестовых вариантов будет описан чуть позже. Сейчас же, отметьте что для того чтобы создать экземпляр такого тестового варианта вызывается его конструктор без аргументов:
 
<sourcesyntaxhighlight lang="python">
testCase = DefaultWidgetSizeTestCase()
</syntaxhighlight>
</source>
 
Подобные тестовые варианты могут быть многочисленными и установка начальных значений для них может повторяться многократно. В примере выше, создание виджета для каждого из 100 тестовых вариантов для виджетов, означает некрасивое повторение кода.
Строка 243:
К счастью, можно избежать таких проблем с кодом установки начальных значений, используя метод '''setUp()''', автоматически вызываемый тестовым каркасом при выполнении теста:
 
<sourcesyntaxhighlight lang="python">
import unittest
 
Строка 260:
self.assertEqual(self.widget.size(), (100,150),
'wrong size after resize')
</syntaxhighlight>
</source>
 
Если метод '''setUp()''' поднимает исключение во время выполнения теста, каркас полагает что в тесте есть ошибка и метод '''runTest()''' не выполняется.
Аналогичными образом можно добавить метод '''tearDown()''' который сбрасывает изменения в начальных установках после выполнения метода '''runTest()'''
 
<sourcesyntaxhighlight lang="python">
class SimpleWidgetTestCase(unittest.TestCase):
def setUp(self):
Строка 273:
self.widget.dispose()
self.widget = None
</syntaxhighlight>
</source>
 
Если метод '''setUp()''' был успешно выполнен, метод '''tearDown()''' будет выполнятся вне зависимости от успешности выполнения '''runtTest()'''.
Строка 280:
Часто множество небольших тестовых вариантов используют одинаковое окружение. В таких случаях, для класса '''SimpleWidgetTestCase''' может создаваться куча подклассов с одним методом, типа '''DefaultWidgetSizeTestCase'''. Эта операция отнимает много времени и отбивает всякое желание ей заниматься, поэтому, аналогично с '''JUnit''', '''unittest''' предоставляет более простой механизм:
 
<sourcesyntaxhighlight lang="python">
import unittest
 
Строка 299:
self.assertEqual(self.widget.size(), (100,150),
'wrong size after resize')
</syntaxhighlight>
</source>
 
В приведенном примере нет метода '''runTest()''', вместо этого есть два разных тестовых метода. Каждый экземпляр класса будут выполнять один из методов '''test_*()''' с созданием и уничтожением '''self.widget''' при запуске тестового метода. При создании экземпляра требуется указать какой тестовый метод следует выполнять. Это достигается передачей названия метода в конструктор.
 
<sourcesyntaxhighlight lang="python">
defaultSizeTestCase = WidgetTestCase('test_default_size')
resizeTestCase = WidgetTestCase('test_resize')
</syntaxhighlight>
</source>
 
Экземпляры тестовых вариантов группируются в соответствии с функциями, которые они тестируют. '''unittest''' предоставляет механизм такой группировки: тестовые наборы, представляемые классом '''TestSuite''' модуля '''unittest''':
 
<sourcesyntaxhighlight lang="python">
widgetTestSuite = unittest.TestSuite()
widgetTestSuite.addTest(WidgetTestCase('test_default_size'))
widgetTestSuite.addTest(WidgetTestCase('test_resize'))
</syntaxhighlight>
</source>
 
Для упрощения выполнения тестов, как мы убедимся чуть позже, рекомендуется создать в каждом тестовом модуле вызываемый объект, возвращающий предварительно созданный тестовый набор:
 
<sourcesyntaxhighlight lang="python">
def suite():
suite = unittest.TestSuite()
Строка 329:
 
return unittest.TestSuite(map(WidgetTestCase, tests))
</syntaxhighlight>
</source>
 
Поскольку создание подкласса '''TestCase''' с несколькими тестовыми функциями со сходными названиями является общей практикой, в '''unittest''' есть класс '''TestLoader''', который можно использовать для автоматизации процесса создания тестового набора и наполнения его отдельными тестами. Например, строка:
 
<sourcesyntaxhighlight lang="python">
suite = unittest.TestLoader().loadTestsFromTestCase(WidgetTestCase)
</syntaxhighlight>
</source>
 
создаст тестовый набор выполняющий методы '''WidgetTestCase.test_default_size()''' и '''WidgetTestCase.test_resize()'''. '''TestLoader''' автоматически находит тестовые методы по префиксу 'test' в названии метода.
Строка 341:
Часто возникает необходимость группировать тестовые наборы, например для выполнения тестов для целой системы сразу. С этим нет никаких сложностей, поскольку экземпляры '''TestSuite''' могут добавляться в '''TestSuite''', так же как и экземпляры '''TestCase'''.
 
<sourcesyntaxhighlight lang="python">
suite1 = module1.TheTestSuite()
suite2 = module2.TheTestSuite()
alltests = unittest.TestSuite([suite1, suite2])
</syntaxhighlight>
</source>
 
Код тестовых вариантов и тестовых наборов может размещаться в тех же модулях, что и код, который они тестируют (таких как '''widget.py'''), но размещение тестового кода в отдельном модуле (таком как '''test_widget.py''') дает ряд преимуществ:
Строка 363:
Для следующей тестовой функции:
 
<sourcesyntaxhighlight lang="python">
def testSomething():
something = makeSomething()
assert something.name is not None
# ...
</syntaxhighlight>
</source>
 
возможно создание экземпляра тестового варианта таким образом:
 
<sourcesyntaxhighlight lang="python">
testcase = unittest.FunctionTestCase(testSomething)
</syntaxhighlight>
</source>
 
При необходимости дополнительного запуска методов установки начального состояния и сброса в ходе выполнения тестового варианта, они должны указываться как в примере:
 
<sourcesyntaxhighlight lang="python">
testcase = unittest.FunctionTestCase(testSomething,
setUp=makeSomethingDB,
tearDown=deleteSomethingDB)
</syntaxhighlight>
</source>
 
Для упрощения использования уже существующих тестов, '''unittest''' поддерживает тесты поднимающие '''AssertionError''' для отображения провала теста. Тем не менее, рекомендуется использовать методы '''TestCase.fail*()''' и '''TestCase.assert*()''', поскольку в будущих версиях '''unittest''' обработка '''AssertionError''' может отличаться.
Строка 397:
Каждый экземпляр TestCase выполняет единственный тестовый метод под названием ''methodName''. Как вы возможно помните, выше приводился пример в котором было что-то вроде этого:
 
<sourcesyntaxhighlight lang="python">
def suite():
suite = unittest.TestSuite()
Строка 403:
suite.addTest(WidgetTestCase('test_resize'))
return suite
</syntaxhighlight>
</source>
 
В нем создаются два экземпляра '''WidgetTestCase''', каждый из которых выполняет единственный тест.
Строка 437:
Командно-строчная программа выполняющая набор тестов, предназначена для реализации простого выполнения тестовых модулей. Простейшим использованием данной функции является включение следующей строки в конец тестового сценария:
 
<sourcesyntaxhighlight lang="python">
if __name__ == '__main__':
unittest.main()
</syntaxhighlight>
</source>
 
Аргумент '''testRunner''' может быть как классом тестового прогонщика, так и уже созданным экземпляром такого класса.