UnitTest Framework - Краткое руководство

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

Модульное тестирование можно выполнить двумя способами:

Ручное тестирование Автоматизированное тестирование

Выполнение тестовых примеров вручную без поддержки каких-либо инструментов известно как ручное тестирование.

  • Поскольку тестовые примеры выполняются человеческими ресурсами, это очень time consuming and tedious.

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

  • Это менее надежно, поскольку тесты не всегда могут быть точными из-за человеческих ошибок.

  • Невозможно программировать для написания сложных тестов, извлекающих скрытую информацию.

Поддержка инструментов и выполнение тестовых примеров с использованием инструмента автоматизации называется автоматическим тестированием.

  • Fast Automation запускает тестовые примеры значительно быстрее, чем человеческие ресурсы.

  • В investment over human resources is less поскольку тестовые примеры выполняются с использованием инструмента автоматизации.

  • Автоматические тесты каждый раз выполняют одни и те же операции и are more reliable.

  • Тестеры can program sophisticated tests для выявления скрытой информации.

JUnit - это среда модульного тестирования для языка программирования Java. JUnit сыграл важную роль в разработке разработки, управляемой тестированием, и является одним из семейства фреймворков модульного тестирования, известных под общим названием xUnit, которые возникли с JUnit. Вы можете найти здесь JUnit Tutorial .

Фреймворк модульного тестирования Python, иногда называемый «PyUnit», представляет собой версию JUnit на языке Python, разработанную Кентом Беком и Эрихом Гаммой. PyUnit является частью стандартной библиотеки Python начиная с версии Python 2.1.

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

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

У вас должен быть достаточный опыт в разработке программного обеспечения с использованием языка Python. Наше руководство по Python - хорошее место для начала изучения Python. Также желательно знание основ тестирования программного обеспечения.

Настройка среды

Классы, необходимые для написания тестов, можно найти в модуле unittest. Если вы используете более старые версии Python (до Python 2.1), модуль можно загрузить сhttp://pyunit.sourceforge.net/. Однако модуль unittest теперь является частью стандартного дистрибутива Python; следовательно, он не требует отдельной установки.

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

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

Для этого unittest поддерживает следующие важные концепции:

  • test fixture- Это подготовка, необходимая для выполнения одного или нескольких тестов и любых связанных действий по очистке. Это может включать, например, создание временных или прокси-баз данных, каталогов или запуск серверного процесса.

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

  • test suite- Это набор тестовых примеров, наборов тестов или и того, и другого. Это используется для агрегирования тестов, которые должны выполняться вместе. Наборы тестов реализованы классом TestSuite.

  • test runner- Это компонент, который управляет выполнением тестов и предоставляет результат пользователю. Бегун может использовать графический интерфейс, текстовый интерфейс или возвращать специальное значение, чтобы указать результаты выполнения тестов.

Создание модульного теста

Для написания простого модульного теста необходимы следующие шаги:

Step 1 - Импортируйте модуль unittest в свою программу.

Step 2- Определите функцию для тестирования. В следующем примере функция add () должна быть протестирована.

Step 3 - Создайте тестовый набор, создав подкласс unittest.TestCase.

Step 4- Определите тест как метод внутри класса. Название метода должно начинаться с "test".

Step 5- Каждый тест вызывает функцию утверждения класса TestCase. Есть много типов утверждений. В следующем примере вызывается функция assertEquals ().

Step 6 - функция assertEquals () сравнивает результат функции add () с аргументом arg2 и выдает ошибку assertionError, если сравнение не удалось.

Step 7 - Наконец, вызовите метод main () из модуля unittest.

import unittest
def add(x,y):
   return x + y
   
class SimpleTest(unittest.TestCase):
   def testadd1(self):
      self.assertEquals(add(4,5),9)
      
if __name__ == '__main__':
   unittest.main()

Step 8 - Запустите указанный выше сценарий из командной строки.

C:\Python27>python SimpleTest.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK

Step 9 - Следующие три могут быть возможными результатами теста -

Старший Нет Сообщение и описание
1

OK

Тест пройден. На консоли отображается «A».

2

FAIL

Тест не проходит и вызывает исключение AssertionError. На консоли отображается "F".

3

ERROR

Тест вызывает исключение, отличное от AssertionError. На консоли отображается "E".

Эти результаты отображаются на консоли как «.», «F» и «E» соответственно.

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

Модуль unittest можно использовать из командной строки для запуска одного или нескольких тестов.

python -m unittest test1
python -m unittest test_module.TestClass
python -m unittest test_module.TestClass.test_method

unittest поддерживает следующие параметры командной строки. Чтобы получить список всех параметров командной строки, используйте следующую команду -

Python –m unittest -h

Старший Нет Вариант и описание
1

-h, --help

Показать это сообщение

2

v, --verbose

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

3

-q, --quiet

Минимальная мощность

4

-f, --failfast

Остановить при первой неудаче

5

-c, --catch

Catch control-C и отображение результатов

6

-b, --buffer

Буфер stdout и stderr во время тестовых запусков

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

TestCase Класс

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

В классе TestCase определены следующие методы:

Старший Нет Метод и описание
1

setUp()

Метод, вызываемый для подготовки тестового прибора. Это вызывается непосредственно перед вызовом тестового метода.

2

tearDown()

Метод вызывается сразу после вызова метода тестирования и записи результата. Это вызывается, даже если тестовый метод вызвал исключение,

3

setUpClass()

Метод класса, вызываемый перед тестами при запуске отдельного класса.

4

tearDownClass()

Метод класса, вызываемый после выполнения тестов в отдельном классе.

5

run(result = None)

Запустите тест, собрав результат в объект результата теста, переданный как результат .

6

skipTest(reason)

Вызов этого метода во время теста или setUp () пропускает текущий тест.

7

debug()

Запустите тест, не собирая результат.

8

shortDescription()

Возвращает однострочное описание теста.

Светильники

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

В следующем примере два теста написаны внутри класса TestCase. Они проверяют результат сложения и вычитания двух значений. Метод setup () инициализирует аргументы на основе shortDescription () каждого теста. teardown () будет выполняться в конце каждого теста.

import unittest

class simpleTest2(unittest.TestCase):
   def setUp(self):
      self.a = 10
      self.b = 20
      name = self.shortDescription()
      if name == "Add":
         self.a = 10
         self.b = 20
         print name, self.a, self.b
      if name == "sub":
         self.a = 50
         self.b = 60
         print name, self.a, self.b
   def tearDown(self):
      print '\nend of test',self.shortDescription()

   def testadd(self):
      """Add"""
      result = self.a+self.b
      self.assertTrue(result == 100)
   def testsub(self):
      """sub"""
      result = self.a-self.b
      self.assertTrue(result == -10)
      
if __name__ == '__main__':
   unittest.main()

Запустите приведенный выше код из командной строки. Это дает следующий результат -

C:\Python27>python test2.py
Add 10 20
F
end of test Add
sub 50 60
end of test sub
.
================================================================
FAIL: testadd (__main__.simpleTest2)
Add
----------------------------------------------------------------------
Traceback (most recent call last):
   File "test2.py", line 21, in testadd
      self.assertTrue(result == 100)
AssertionError: False is not true
----------------------------------------------------------------------
Ran 2 tests in 0.015s

FAILED (failures = 1)

Класс Fixture

У класса TestCase есть метод setUpClass (), который можно переопределить для выполнения перед выполнением отдельных тестов внутри класса TestCase. Точно так же метод tearDownClass () будет выполнен после всех тестов в классе. Оба метода являются методами класса. Следовательно, они должны быть украшены директивой @classmethod.

В следующем примере демонстрируется использование этих методов класса -

import unittest

class TestFixtures(unittest.TestCase):

   @classmethod
   def setUpClass(cls):
      print 'called once before any tests in class'

   @classmethod
   def tearDownClass(cls):
      print '\ncalled once after all tests in class'

   def setUp(self):
      self.a = 10
      self.b = 20
      name = self.shortDescription()
      print '\n',name
   def tearDown(self):
      print '\nend of test',self.shortDescription()

   def test1(self):
      """One"""
      result = self.a+self.b
      self.assertTrue(True)
   def test2(self):
      """Two"""
      result = self.a-self.b
      self.assertTrue(False)
      
if __name__ == '__main__':
unittest.main()

TestSuite Класс

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

Следующие шаги связаны с созданием и запуском набора тестов.

Step 1 - Создайте экземпляр класса TestSuite.

suite = unittest.TestSuite()

Step 2 - Добавить тесты внутри класса TestCase в наборе.

suite.addTest(testcase class)

Step 3 - Вы также можете использовать метод makeSuite () для добавления тестов из класса

suite = unittest.makeSuite(test case class)

Step 4 - В комплект также можно добавить индивидуальные тесты.

suite.addTest(testcaseclass(""testmethod")

Step 5 - Создайте объект класса TestTestRunner.

runner = unittest.TextTestRunner()

Step 6 - Вызвать метод run () для запуска всех тестов в наборе

runner.run (suite)

В классе TestSuite определены следующие методы:

Старший Нет Метод и описание
1

addTest()

Добавляет метод тестирования в набор тестов.

2

addTests()

Добавляет тесты из нескольких классов TestCase.

3

run()

Запускает тесты, связанные с этим набором, собирая результат в объект результата теста

4

debug()

Запускает тесты, связанные с этим набором, без сбора результатов.

5

countTestCases()

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

В следующем примере показано, как использовать класс TestSuite -

import unittest
class suiteTest(unittest.TestCase):
   def setUp(self):
      self.a = 10
      self.b = 20
      
   def testadd(self):
      """Add"""
      result = self.a+self.b
      self.assertTrue(result == 100)
   def testsub(self):
      """sub"""
      result = self.a-self.b
      self.assertTrue(result == -10)
      
def suite():
   suite = unittest.TestSuite()
##   suite.addTest (simpleTest3("testadd"))
##   suite.addTest (simpleTest3("testsub"))
   suite.addTest(unittest.makeSuite(simpleTest3))
   return suite
   
if __name__ == '__main__':
   runner = unittest.TextTestRunner()
   test_suite = suite()
   runner.run (test_suite)

Вы можете поэкспериментировать с методом addTest (), раскомментировав строки и оператор комментария с методом makeSuite ().

TestLoader Класс

В пакете unittest есть класс TestLoader, который используется для создания наборов тестов из классов и модулей. По умолчанию экземпляр unittest.defaultTestLoader создается автоматически при вызове метода unittest.main (0. Явный экземпляр, однако, позволяет настраивать определенные свойства.

В следующем коде тесты из двух классов собираются в список с помощью объекта TestLoader.

import unittest
testList = [Test1, Test2]
testLoad = unittest.TestLoader()

TestList = []
for testCase in testList:
   testSuite = testLoad.loadTestsFromTestCase(testCase)
   TestList.append(testSuite)
   
newSuite = unittest.TestSuite(TestList)
runner = unittest.TextTestRunner()
runner.run(newSuite)

В следующей таблице показан список методов класса TestLoader -

S.No Метод и описание
1

loadTestsFromTestCase()

Вернуть набор всех тестовых случаев, содержащихся в классе TestCase

2

loadTestsFromModule()

Вернуть набор всех тестов, содержащихся в данном модуле.

3

loadTestsFromName()

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

4

discover()

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

TestResult Класс

Этот класс используется для сбора информации об успешных и неудачных тестах. Объект TestResult хранит результаты набора тестов. Экземпляр TestResult возвращается методом TestRunner.run ().

Экземпляры TestResult имеют следующие атрибуты -

Старший Нет Атрибут и описание
1

Errors

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

2

Failures

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

3

Skipped

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

4

wasSuccessful()

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

5

stop()

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

6

startTestRun()

Вызывается один раз перед выполнением любых тестов.

7

stopTestRun()

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

8

testsRun

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

9

Buffer

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

Следующий код выполняет набор тестов -

if __name__ == '__main__':
   runner = unittest.TextTestRunner()
   test_suite = suite()
   result = runner.run (test_suite)
   
   print "---- START OF TEST RESULTS"
   print result

   print "result::errors"
   print result.errors

   print "result::failures"
   print result.failures

   print "result::skipped"
   print result.skipped

   print "result::successful"
   print result.wasSuccessful()
   
   print "result::test-run"
   print result.testsRun
   print "---- END OF TEST RESULTS"

Код при выполнении отображает следующий вывод -

---- START OF TEST RESULTS
<unittest.runner.TextTestResult run = 2 errors = 0 failures = 1>
result::errors
[]
result::failures
[(<__main__.suiteTest testMethod = testadd>, 'Traceback (most recent call last):\n
   File "test3.py", line 10, in testadd\n 
   self.assertTrue(result == 100)\nAssert
   ionError: False is not true\n')]
result::skipped
[]
result::successful
False
result::test-run
2
---- END OF TEST RESULTS

Среда тестирования Python использует встроенную функцию Python assert (), которая проверяет определенное условие. Если утверждение не выполняется, возникает ошибка AssertionError. Система тестирования затем идентифицирует тест как Failure. Другие исключения обрабатываются как ошибка.

Следующие три набора функций утверждения определены в модуле unittest -

  • Базовые логические утверждения
  • Сравнительные утверждения
  • Утверждения для коллекций

Базовые функции утверждения оценивают, является ли результат операции истинным или ложным. Все методы assert принимаютmsg аргумент, который, если он указан, используется как сообщение об ошибке при сбое.

Старший Нет Метод и описание
1

assertEqual(arg1, arg2, msg = None)

Убедитесь, что arg1 и arg2 равны. Если значения не совпадают, тест завершится неудачно.

2

assertNotEqual(arg1, arg2, msg = None)

Проверьте, что arg1 и arg2 не равны. Если значения действительно равны, тест не пройден.

3

assertTrue(expr, msg = None)

Проверьте, что expr истинно. Если false, тест не пройден

4

assertFalse(expr, msg = None)

Проверьте, что выражение ложно. Если это правда, тест не пройден

5

assertIs(arg1, arg2, msg = None)

Проверьте, что arg1 и arg2 оценивают один и тот же объект.

6

assertIsNot(arg1, arg2, msg = None)

Проверьте, что arg1 и arg2 не оценивают один и тот же объект.

7

assertIsNone(expr, msg = None)

Проверьте, что expr - None. Если нет, тест не пройден.

8

assertIsNotNone(expr, msg = None)

Проверьте, что expr не равно None. Если нет, тест не пройден

9

assertIn(arg1, arg2, msg = None)

Проверьте, что arg1 находится в arg2 .

10

assertNotIn(arg1, arg2, msg = None)

Убедитесь, что arg1 не входит в arg2 .

11

assertIsInstance(obj, cls, msg = None)

Проверьте, что obj является экземпляром cls

12

assertNotIsInstance(obj, cls, msg = None)

Проверьте, что obj не является экземпляром cls

Некоторые из вышеуказанных функций утверждения реализованы в следующем коде -

import unittest

class SimpleTest(unittest.TestCase):
   def test1(self):
      self.assertEqual(4 + 5,9)
   def test2(self):
      self.assertNotEqual(5 * 2,10)
   def test3(self):
      self.assertTrue(4 + 5 == 9,"The result is False")
   def test4(self):
      self.assertTrue(4 + 5 == 10,"assertion fails")
   def test5(self):
      self.assertIn(3,[1,2,3])
   def test6(self):
      self.assertNotIn(3, range(5))

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

Когда приведенный выше сценарий запущен, test2, test4 и test6 покажут ошибку, а остальные будут выполнены успешно.

FAIL: test2 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
   File "C:\Python27\SimpleTest.py", line 9, in test2
      self.assertNotEqual(5*2,10)
AssertionError: 10 == 10

FAIL: test4 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
   File "C:\Python27\SimpleTest.py", line 13, in test4
      self.assertTrue(4+5==10,"assertion fails")
AssertionError: assertion fails

FAIL: test6 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
   File "C:\Python27\SimpleTest.py", line 17, in test6
      self.assertNotIn(3, range(5))
AssertionError: 3 unexpectedly found in [0, 1, 2, 3, 4]

----------------------------------------------------------------------            
Ran 6 tests in 0.001s                                                             
                                                                                  
FAILED (failures = 3)

Второй набор функций утверждения: comparative asserts −

  • assertAlmostEqual (первое, второе, места = 7, сообщение = Нет, дельта = Нет)

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

  • assertNotAlmostEqual (первое, второе, места, сообщение, дельта)

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

    В обеих приведенных выше функциях, если вместо разрядов указывается дельта, то разница между первым и вторым должна быть меньше или равна (или больше) дельты.

    Предоставление и дельты, и мест вызывает ошибку TypeError.

  • assertGreater (первое, второе, сообщение = Нет)

    Проверьте, что первое больше второго в зависимости от имени метода. В противном случае тест не состоится.

  • assertGreaterEqual (первое, второе, сообщение = Нет)

    Проверьте, что первое больше или равно второму в зависимости от имени метода. Если нет, тест не пройдёт

  • assertLess (первое, второе, сообщение = Нет)

    Проверьте, что первое меньше второго в зависимости от имени метода. Если нет, тест не пройдёт

  • assertLessEqual (первое, второе, сообщение = Нет)

    Проверьте, что первое меньше или равно второму в зависимости от имени метода. В противном случае тест не состоится.

  • assertRegexpMatches (текст, регулярное выражение, сообщение = Нет)

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

  • assertNotRegexpMatches (текст, регулярное выражение, сообщение = Нет)

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

Функции утверждения реализованы в следующем примере -

import unittest
import math
import re

class SimpleTest(unittest.TestCase):
   def test1(self):
      self.assertAlmostEqual(22.0/7,3.14)
   def test2(self):
      self.assertNotAlmostEqual(10.0/3,3)
   def test3(self):
      self.assertGreater(math.pi,3)
   def test4(self):
      self.assertNotRegexpMatches("Tutorials Point (I) Private Limited","Point")

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

Приведенный выше сценарий сообщает test1 и test4 как Failure. В test1 деление 22/7 находится вне 7 десятичных знаков 3,14. Точно так же, поскольку второй аргумент совпадает с текстом в первом аргументе, test4 приводит к AssertionError.

=====================================================FAIL: test1 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
   File "asserttest.py", line 7, in test1
      self.assertAlmostEqual(22.0/7,3.14)
AssertionError: 3.142857142857143 != 3.14 within 7 places
================================================================
FAIL: test4 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
   File "asserttest.py", line 13, in test4
      self.assertNotRegexpMatches("Tutorials Point (I) Private Limited","Point")
AssertionError: Regexp matched: 'Point' matches 'Point' in 'Tutorials Point (I)
Private Limited'
----------------------------------------------------------------------

Ran 4 tests in 0.001s                                                             
                                                                                  
FAILED (failures = 2)

Утверждение для коллекций

Этот набор функций assert предназначен для использования с типами данных коллекции в Python, такими как List, Tuple, Dictionary и Set.

Старший Нет Метод и описание
1

assertListEqual (list1, list2, msg = None)

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

2

assertTupleEqual (tuple1, tuple2, msg = None)

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

3

assertSetEqual (set1, set2, msg = None)

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

4

assertDictEqual (expected, actual, msg = None)

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

В следующем примере реализуются вышеуказанные методы -

import unittest

class SimpleTest(unittest.TestCase):
   def test1(self):
      self.assertListEqual([2,3,4], [1,2,3,4,5])
   def test2(self):
      self.assertTupleEqual((1*2,2*2,3*2), (2,4,6))
   def test3(self):
      self.assertDictEqual({1:11,2:22},{3:33,2:22,1:11})

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

В приведенном выше примере test1 и test3 показывают AssertionError. Сообщение об ошибке отображает различия в объектах List и Dictionary.

FAIL: test1 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
   File "asserttest.py", line 5, in test1
      self.assertListEqual([2,3,4], [1,2,3,4,5])
AssertionError: Lists differ: [2, 3, 4] != [1, 2, 3, 4, 5]

First differing element 0:
2
1

Second list contains 2 additional elements.
First extra element 3:
4

- [2, 3, 4]
+ [1, 2, 3, 4, 5]
? +++       +++

FAIL: test3 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
   File "asserttest.py", line 9, in test3
      self.assertDictEqual({1:11,2:22},{3:33,2:22,1:11})
AssertionError: {1: 11, 2: 22} != {1: 11, 2: 22, 3: 33}
- {1: 11, 2: 22}
+ {1: 11, 2: 22, 3: 33}
?              +++++++
                                                                                  
----------------------------------------------------------------------            
Ran 3 tests in 0.001s                                                             
                                                                                  
FAILED (failures = 2)

В классе TestLoader есть функция discover (). Среда тестирования Python использует это для простого обнаружения тестов. Для обеспечения совместимости модули и пакеты, содержащие тесты, должны быть импортированы из каталога верхнего уровня.

Ниже приводится базовое использование тестового обнаружения в командной строке.

Python –m unittest discover

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

Старший Нет Опции и описание
1

-v, --verbose

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

2

-s, --start-directory

каталог Каталог для начала обнаружения (по умолчанию)

3

-p, --pattern

шаблон Шаблон для соответствия тестовым файлам (по умолчанию test * .py)

4

-t, --top-level-directory

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

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

C:\python27>python –m unittest –v –s "c:\test" –p "assert*.py"

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

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

Поддержка пропуска тестов была добавлена ​​начиная с Python 2.7. Можно как условно, так и безоговорочно пропустить отдельный метод тестирования или класс TestCase. Фреймворк позволяет пометить определенный тест как «ожидаемый сбой». Этот тест завершится неудачно, но не будет засчитан как неудачный в TestResult.

Чтобы безоговорочно пропустить метод, можно использовать следующий метод класса unittest.skip ():

import unittest

   def add(x,y):
      return x+y

class SimpleTest(unittest.TestCase):
   @unittest.skip("demonstrating skipping")
   def testadd1(self):
      self.assertEquals(add(4,5),9)

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

Поскольку skip () - это метод класса, перед ним стоит символ @. Метод принимает один аргумент: сообщение журнала с описанием причины пропуска.

Когда приведенный выше скрипт выполняется, на консоли отображается следующий результат:

C:\Python27>python skiptest.py
s
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK (skipped = 1)

Символ "s" означает, что тест был пропущен.

Альтернативный синтаксис для пропуска теста - использование метода экземпляра skipTest () внутри тестовой функции.

def testadd2(self):
   self.skipTest("another method for skipping")
   self.assertTrue(add(4 + 5) == 10)

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

Старший Нет Метод и описание
1

unittest.skip(reason)

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

2

unittest.skipIf(condition, reason)

Пропустить оформленный тест, если условие верно.

3

unittest.skipUnless(condition, reason)

Пропустите оформленный тест, если условие не выполняется.

4

unittest.expectedFailure()

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

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

import unittest

class suiteTest(unittest.TestCase):
   a = 50
   b = 40
   
   def testadd(self):
      """Add"""
      result = self.a+self.b
      self.assertEqual(result,100)

   @unittest.skipIf(a>b, "Skip over this routine")
   def testsub(self):
      """sub"""
      result = self.a-self.b
      self.assertTrue(result == -10)
   
   @unittest.skipUnless(b == 0, "Skip over this routine")
   def testdiv(self):
      """div"""
      result = self.a/self.b
      self.assertTrue(result == 1)

   @unittest.expectedFailure
   def testmul(self):
      """mul"""
      result = self.a*self.b
      self.assertEqual(result == 0)

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

В приведенном выше примере методы testsub () и testdiv () будут пропущены. В первом случае a> b верно, а во втором случае b == 0 неверно. С другой стороны, testmul () отмечен как ожидаемый сбой.

При запуске вышеуказанного сценария два пропущенных теста показывают «s», а ожидаемый сбой отображается как «x».

C:\Python27>python skiptest.py
Fsxs
================================================================
FAIL: testadd (__main__.suiteTest)
Add
----------------------------------------------------------------------
Traceback (most recent call last):
   File "skiptest.py", line 9, in testadd
      self.assertEqual(result,100)
AssertionError: 90 != 100

----------------------------------------------------------------------
Ran 4 tests in 0.000s

FAILED (failures = 1, skipped = 2, expected failures = 1)

Платформа тестирования Python предоставляет следующие методы утверждения для проверки возникновения исключений.

assertRaises (исключение, вызываемый, * аргументы, ** kwds)

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

В приведенном ниже примере определена тестовая функция, чтобы проверить, возникает ли ошибка ZeroDivisionError.

import unittest

def div(a,b):
   return a/b
class raiseTest(unittest.TestCase):
   def testraise(self):
      self.assertRaises(ZeroDivisionError, div, 1,0)

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

Функция testraise () использует функцию assertRaises (), чтобы узнать, происходит ли деление на ноль при вызове функции div (). Приведенный выше код вызовет исключение. Но меняет аргументы функции div () следующим образом:

self.assertRaises(ZeroDivisionError, div, 1,1)

Когда код запускается с этими изменениями, тест не проходит, так как ZeroDivisionError не возникает.

F
================================================================
FAIL: testraise (__main__.raiseTest)
----------------------------------------------------------------------
Traceback (most recent call last):
   File "raisetest.py", line 7, in testraise
      self.assertRaises(ZeroDivisionError, div, 1,1)
AssertionError: ZeroDivisionError not raised

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (failures = 1)

assertRaisesRegexp (исключение, регулярное выражение, вызываемый, * args, ** kwds)

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

В следующем примере показано, как используется assertRaisesRegexp ():

import unittest
import re

class raiseTest(unittest.TestCase):
   def testraiseRegex(self):
      self.assertRaisesRegexp(TypeError, "invalid", reg,"Point","TutorialsPoint")
      
if __name__ == '__main__':
   unittest.main()

Здесь тест testraseRegex () не является первым аргументом. «Точка» находится во второй строке аргумента.

================================================================
FAIL: testraiseRegex (__main__.raiseTest)
----------------------------------------------------------------------
Traceback (most recent call last):
   File "C:/Python27/raiseTest.py", line 11, in testraiseRegex
      self.assertRaisesRegexp(TypeError, "invalid", reg,"Point","TutorialsPoint")
AssertionError: TypeError not raised
----------------------------------------------------------------------

Однако изменение показано ниже -

self.assertRaisesRegexp(TypeError, "invalid", reg,123,"TutorialsPoint")

Будет выброшено исключение TypeError. Следовательно, будет отображаться следующий результат -

================================================================
FAIL: testraiseRegex (__main__.raiseTest)
----------------------------------------------------------------------
Traceback (most recent call last):
   File "raisetest.py", line 11, in testraiseRegex
      self.assertRaisesRegexp(TypeError, "invalid", reg,123,"TutorialsPoint")
AssertionError: "invalid" does not match 
   "first argument must be string or compiled pattern"
----------------------------------------------------------------------

Junit, среда модульного тестирования Java (Pyunit - это реализация JUnit), имеет удобную возможность тайм-аута. Если проверка занимает больше указанного времени, она будет отмечена как неудавшаяся.

Среда тестирования Python не поддерживает тайм-аут. Однако эту работу может выполнить модуль третьей части, называемый timeout-decorator.

Загрузите и установите модуль из -

https://pypi.python.org/packages/source/t/timeout-decorator/timeout-decorator-0.3.2.tar.gz

  • Импортировать timeout_decorator в код
  • Поставить декоратор тайм-аута перед тестом
  • @timeout_decorator.timeout(10)

Если тестовый метод ниже этой строки занимает больше указанного здесь тайм-аута (10 минут), возникает ошибка TimeOutError. Например -

import time
import timeout_decorator

class timeoutTest(unittest.TestCase):

   @timeout_decorator.timeout(5)
   def testtimeout(self):
      print "Start"
   for i in range(1,10):
      time.sleep(1)
      print "%d seconds have passed" % i
      
if __name__ == '__main__':
   unittest.main()

unittest2 - это резервная копия дополнительных функций, добавленных в среду тестирования Python в Python 2.7 и новее. Он протестирован для работы на Python 2.6, 2.7 и 3. *. Последнюю версию можно скачать сhttps://pypi.python.org/pypi/unittest2

Чтобы использовать unittest2 вместо unittest, просто замените import unittest на import unittest2.

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

Ниже приведены новые функции unittest2 -

  • addCleanups для лучшего управления ресурсами

  • Содержит много новых методов утверждения

  • assertRaises в качестве диспетчера контекста с последующим доступом к исключению

  • Имеет приспособления уровня модуля, такие как setUpModule и tearDownModule

  • Включает в себя load_tests протокол для загрузки тестов из модулей или пакетов

  • startTestRun и stopTestRun методы на TestResult

В Python 2.7 вы вызываете функции командной строки unittest (включая обнаружение тестов) с помощью python -m unittest <args>.

Вместо этого unittest2 поставляется со скриптом unit2.

unit2 discover
unit2 -v test_module

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

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

Следующие служебные функции включают функциональность обработки control-c в рамках тестовой среды:

unittest.installHandler ()

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

unittest.registerResult (результат)

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

unittest.removeResult (результат)

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

unittest.removeHandler (функция = Нет)

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

GUI Test Runner

Модуль unittest устанавливается для интерактивного обнаружения и запуска тестов. Эта утилита, скрипт Python inittestgui.py, использует модуль Tkinter, который является портом Python для набора графических инструментов TK. Это дает простой в использовании графический интерфейс для обнаружения и запуска тестов.

Python unittestgui.py

Нажмите кнопку "Обнаружить тесты". Появится небольшое диалоговое окно, в котором вы можете выбрать каталог и модули, из которых будет запускаться тест.

Наконец, нажмите кнопку «Пуск». Тесты будут обнаружены по выбранному пути и именам модулей, и на панели результатов будут отображаться результаты.

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

Если вы не нашли эту утилиту в установке Python, вы можете получить ее на странице проекта. http://pyunit.sourceforge.net/.

Аналогичная утилита на основе инструментария wxpython также доступна там.

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

Доктест может быть очень полезен в следующих сценариях -

  • Чтобы проверить актуальность документации модуля, убедившись, что все интерактивные примеры по-прежнему работают, как задокументировано.

  • Выполнить регрессионное тестирование, убедившись, что интерактивные примеры из тестового файла или тестового объекта работают должным образом.

  • Написать учебную документацию для пакета, обильно иллюстрированную примерами ввода-вывода

В Python «docstring» - это строковый литерал, который появляется как первое выражение в классе, функции или модуле. Он игнорируется при выполнении набора, но распознается компилятором и помещается в__doc__атрибут включающего класса, функции или модуля. Поскольку он доступен через интроспекцию, это каноническое место для документации объекта.

Это обычная практика - помещать примеры использования различных частей кода Python внутри строки документации. Модуль doctest позволяет проверить актуальность этих строк документации с периодическими изменениями кода.

В следующем коде функция факториала определяется вкраплениями с примером использования. Чтобы проверить правильность использования примера, вызовите функцию testmod () в модуле doctest.

"""
This is the "example" module.

The example module supplies one function, factorial(). For example,

>>> factorial(5)
120
"""

def factorial(x):
   """Return the factorial of n, an exact integer >= 0.
   >>> factorial(-1)
   Traceback (most recent call last):
      ...
   ValueError: x must be >= 0
   """
   
   if not x >= 0:
      raise ValueError("x must be >= 0")
   f = 1
   for i in range(1,x+1):
      f = f*i
   return f
   
if __name__ == "__main__":
   import doctest
   doctest.testmod()

Введите и сохраните приведенный выше сценарий как FactDocTest.py и попробуйте выполнить этот сценарий из командной строки.

Python FactDocTest.py

Никакие выходные данные не будут показаны, если пример не завершится ошибкой. Теперь измените командную строку на следующую -

Python FactDocTest.py –v

Консоль теперь покажет следующий вывод -

C:\Python27>python FactDocTest.py -v
Trying:
   factorial(5)
Expecting:
   120
ok
Trying:
   factorial(-1)
Expecting:
   Traceback (most recent call last):
      ...
   ValueError: x must be >= 0
ok
2 items passed all tests:
   1 tests in __main__
   1 tests in __main__.factorial
2 tests in 2 items.
2 passed and 0 failed.
Test passed.

Если же, с другой стороны, код функции factorial () не дает ожидаемого результата в строке документации, будет отображен результат сбоя. Например, измените f = 2 вместо f = 1 в приведенном выше сценарии и снова запустите doctest. Результат будет следующим -

Trying:
   factorial(5)
Expecting:
   120
**********************************************************************
File "docfacttest.py", line 6, in __main__
Failed example:
factorial(5)
Expected:
   120
Got:
   240
Trying:
   factorial(-1)
Expecting:
   Traceback (most recent call last):
      ...
   ValueError: x must be >= 0
ok
1 items passed all tests:
   1 tests in __main__.factorial
**********************************************************************
1 items had failures:
   1 of 1 in __main__
2 tests in 2 items.
1 passed and 1 failed.
***Test Failed*** 1 failures.

Доктест: проверка примеров в текстовом файле

Еще одно простое применение doctest - тестирование интерактивных примеров в текстовом файле. Это можно сделать с помощью функции testfile ().

Следующий текст хранится в текстовом файле с именем example.txt.

Using ''factorial''
-------------------
This is an example text file in reStructuredText format. First import
''factorial'' from the ''example'' module:
   >>> from example import factorial
Now use it:
   >>> factorial(5)
   120

Содержимое файла рассматривается как строка документации. Чтобы проверить примеры в текстовом файле, используйте функцию testfile () модуля doctest.

def factorial(x):
   if not x >= 0:
      raise ValueError("x must be >= 0")
   f = 1
   for i in range(1,x+1):
      f = f*i
   return f
   
if __name__ == "__main__":
   import doctest
   doctest.testfile("example.txt")
  • Как и в случае с testmod (), testfile () ничего не будет отображать, если пример не завершится ошибкой. Если пример не работает, то пример (ы) сбоя и причина (ы) сбоя (ов) выводятся на консоль в том же формате, что и testmod ().

  • В большинстве случаев копирование и вставка сеанса интерактивной консоли работает нормально, но doctest не пытается точно эмулировать какую-либо конкретную оболочку Python.

  • Любой ожидаемый вывод должен сразу следовать за последней строкой '>>>' или '...', содержащей код, а ожидаемый вывод (если таковой имеется) распространяется на следующую строку '>>>' или полностью пробелами.

  • Ожидаемый вывод не может содержать строку, состоящую только из пробелов, поскольку такая строка используется для обозначения конца ожидаемого вывода. Если ожидаемый вывод действительно содержит пустую строку, вставьте <BLANKLINE> в ваш пример doctest каждый раз, когда ожидается пустая строка.

API doctest вращается вокруг следующих двух контейнерных классов, используемых для хранения интерактивных примеров из строк документации:

  • Example - Одиночный оператор Python в паре с ожидаемым результатом.

  • DocTest - Коллекция примеров, обычно извлекаемых из одной строки документации или текстового файла.

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

  • DocTestFinder - Находит все строки документации в данном модуле и использует DocTestParser для создания DocTest из каждой строки документации, содержащей интерактивные примеры.

  • DocTestParser - Создает объект doctest из строки (например, строки документации объекта).

  • DocTestRunner - Выполняет примеры в doctest и использует OutputChecker для проверки их вывода.

  • OutputChecker - Сравнивает фактический результат теста doctest с ожидаемым и решает, совпадают ли они.

DocTestFinder Класс

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

Этот класс определяет метод find (). Он возвращает список тестов DocTests, которые определены строкой документации объекта или строками документации любого из содержащихся в нем объектов.

DocTestParser Класс

Это класс обработки, используемый для извлечения интерактивных примеров из строки и использования их для создания объекта DocTest. Этот класс определяет следующие методы -

  • get_doctest() - Извлеките все примеры тестов из заданной строки и соберите их в DocTest объект.

  • get_examples(string[, name]) - Извлечь все примеры тестов из заданной строки и вернуть их в виде списка Exampleобъекты. Номера строк начинаются с 0. Необязательное имя аргумента - это имя, идентифицирующее эту строку, и используется только для сообщений об ошибках.

  • parse(string[, name]) - Разделите данную строку на примеры и промежуточный текст и верните их как список чередующихся Examplesи струны. Номера строк дляExamplesначинаются с 0. Необязательное имя аргумента - это имя, идентифицирующее эту строку, и используется только для сообщений об ошибках.

DocTestRunner Класс

Это класс обработки, используемый для выполнения и проверки интерактивных примеров в DocTest. В нем определены следующие методы -

report_start ()

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

report_success ()

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

report_failure ()

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

report_unexpected_exception ()

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

запустить (тест)

Запустите примеры в тесте (объект DocTest) и отобразите результаты с помощью функции записи out .

подвести итог ([подробный])

Распечатайте сводку всех тестовых случаев, которые были запущены этим DocTestRunner, и верните именованный кортеж TestResults (сбой, попытка). Необязательный многословный аргумент определяет, насколько подробным будет резюме. Если уровень детализации не указан, используется уровень детализации DocTestRunner.

OutputChecker Класс

Этот класс используется для проверки того, соответствует ли фактический вывод из примера doctest ожидаемому.

В этом классе определены следующие методы:

check_output ()

Возвращение Trueесли фактический результат из примера ( got ) совпадает с ожидаемым результатом ( хотите ). Эти строки всегда считаются совпадающими, если они идентичны; но в зависимости от того, какие флажки опций использует средство выполнения тестов, также возможно несколько типов неточного соответствия. См. Раздел Флаги опций и директивы для получения дополнительной информации о флагах опций.

output_difference ()

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

Интеграция DocTest с Unittest

Модуль doctest предоставляет две функции, которые можно использовать для создания наборов модульных тестов из модулей и текстовых файлов, содержащих тесты. Чтобы интегрироваться с обнаружением тестов unittest, включите функцию load_tests () в свой тестовый модуль -

import unittest
import doctest
import doctestexample

def load_tests(loader, tests, ignore):
   tests.addTests(doctest.DocTestSuite(doctestexample))
   return tests

Будет сформирован комбинированный TestSuite тестов из unittest и doctest, и теперь он может быть выполнен с помощью метода main () или run () модуля unittest.

Ниже приведены две основные функции для создания unittest.TestSuite экземпляры из текстовых файлов и модулей с тестами -

doctest.DocFileSuite ()

Он используется для преобразования тестов doctest из одного или нескольких текстовых файлов в unittest.TestSuite. Возвращенный unittest.TestSuite должен запускаться платформой unittest и запускать интерактивные примеры в каждом файле. Если какой-либо из примеров в файле терпит неудачу, то синтезированный модульный тест терпит неудачу, иfailureException Возникает исключение, показывающее имя файла, содержащего тест, и (иногда приблизительный) номер строки.

doctest.DocTestSuite ()

Он используется для преобразования тестов doctest для модуля в unittest.TestSuite.

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

Под покровом DocTestSuite () создает unittest.TestSuite из экземпляров doctest.DocTestCase, а DocTestCase является подклассом unittest.TestCase.

Точно так же DocFileSuite () создает unittest.TestSuite из экземпляров doctest.DocFileCase, а DocFileCase является подклассом DocTestCase.

Таким образом, оба способа создания unittest.TestSuite запускают экземпляры DocTestCase. Когда вы запускаете функции doctest самостоятельно, вы можете напрямую управлять используемыми параметрами doctest, передавая флаги опций функциям doctest.

Однако, если вы пишете фреймворк unittest, unittest в конечном итоге контролирует, когда и как запускаются тесты. Автор фреймворка обычно хочет управлять параметрами отчетов doctest (возможно, например, указанными параметрами командной строки), но нет способа передать параметры через unittest участникам тестирования doctest.

В 2004 году Хольгер Крекель переименовал свой stdпакет, имя которого часто путали с именем стандартной библиотеки, поставляемой с Python, на имя (лишь немного менее запутанное) py. Хотя пакет содержит несколько подпакетов, теперь он почти полностью известен своей структурой py.test.

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

py.test - это не шаблонная альтернатива стандартному модулю Python unittest. Несмотря на то, что это полнофункциональный и расширяемый инструмент тестирования, он может похвастаться простым синтаксисом. Создать набор тестов так же просто, как написать модуль с парой функций.

py.test работает во всех операционных системах POSIX и WINDOWS (XP / 7/8) с Python версии 2.6 и выше.

Установка

Используйте следующий код для загрузки модуля pytest из текущего дистрибутива Python, а также утилиты py.test.exe. Тесты можно запускать с использованием обоих.

pip install pytest

Применение

Вы можете просто использовать оператор assert для подтверждения ожиданий теста. Самоанализ assert в pytest будет интеллектуально сообщать промежуточные значения выражения assert, освобождая вас от необходимости изучать множество именJUnit legacy methods.

# content of test_sample.py
def func(x):
   return x + 1
   
def test_answer():
   assert func(3) == 5

Используйте следующую командную строку для запуска вышеуказанного теста. После запуска теста на консоли отображается следующий результат:

C:\Python27>scripts\py.test -v test_sample.py
============================= test session starts =====================
platform win32 -- Python 2.7.9, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 -- C:\Pyth
on27\python.exe
cachedir: .cache
rootdir: C:\Python27, inifile:
collected 1 items
test_sample.py::test_answer FAILED
================================== FAILURES =====================
_________________________________ test_answer _________________________________
   def test_answer():
>  assert func(3) == 5
E     assert 4 == 5
E     + where 4 = func(3)
test_sample.py:7: AssertionError
========================== 1 failed in 0.05 seconds ====================

Тест также можно запустить из командной строки, включив модуль pytest с помощью переключателя –m.

python -m pytest test_sample.py

Группирование нескольких тестов в класс

Когда у вас появляется больше, чем несколько тестов, часто имеет смысл сгруппировать тесты логически, по классам и модулям. Напишем класс, содержащий два теста -

class TestClass:
   def test_one(self):
      x = "this"
      assert 'h' in x
   def test_two(self):
      x = "hello"
      assert hasattr(x, 'check')

Будет отображен следующий результат теста -

C:\Python27>scripts\py.test -v test_class.py
============================= test session starts =====================
platform win32 -- Python 2.7.9, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 -- C:\Pyt
on27\python.exe
cachedir: .cache
rootdir: C:\Python27, inifile:
collected 2 items
test_class.py::TestClass::test_one PASSED
test_class.py::TestClass::test_two FAILED
================================== FAILURES =====================
_____________________________ TestClass.test_two ______________________________
self = <test_class.TestClass instance at 0x01309DA0>

   def test_two(self):
      x = "hello"
>  assert hasattr(x, 'check')
E     assert hasattr('hello', 'check')

test_class.py:7: AssertionError
===================== 1 failed, 1 passed in 0.06 seconds ======================

Проект носа вышел в 2005 году, через год после py.testполучил свой современный облик. Он был написан Джейсоном Пеллерином для поддержки тех же тестовых идиом, которые были впервые предложены py.test, но в пакете, который проще установить и поддерживать.

В nose модуль можно установить с помощью утилиты pip

pip install nose

Это установит модуль носа в текущем дистрибутиве Python, а также файл носа test.exe, что означает, что тест можно запустить с помощью этой утилиты, а также с помощью переключателя –m.

C:\python>nosetests –v test_sample.py
Or
C:\python>python –m nose test_sample.py

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

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

Как и в случае с модулем unittest, nose поддерживает фикстуры на уровне пакета, модуля, класса и тестового примера, поэтому дорогостоящая инициализация может выполняться как можно реже.

Основное использование

Давайте рассмотрим файл nodetest.py, аналогичный используемому ранее скрипту -

# content of nosetest.py
def func(x):
   return x + 1
   
def test_answer():
   assert func(3) == 5

Чтобы запустить вышеуказанный тест, используйте следующий синтаксис командной строки -

C:\python>nosetests –v nosetest.py

Вывод, отображаемый на консоли, будет следующим:

nosetest.test_answer ... FAIL
================================================================
FAIL: nosetest.test_answer
----------------------------------------------------------------------
Traceback (most recent call last):
   File "C:\Python34\lib\site-packages\nose\case.py", line 198, in runTest
      self.test(*self.arg)
   File "C:\Python34\nosetest.py", line 6, in test_answer
      assert func(3) == 5
AssertionError
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (failures = 1)

nose можно интегрировать с DocTest с помощью with-doctest опция в командной строке athe bove.

\nosetests --with-doctest -v nosetest.py

Вы можете использовать nose в тестовом скрипте -

import nose
nose.main()

Если вы не хотите, чтобы тестовый сценарий завершался с 0 в случае успеха и 1 в случае неудачи (например, unittest.main), используйте вместо этого нос.run () -

import nose
result = nose.run()

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

noseподдерживает фикстуры (методы установки и удаления) на уровне пакета, модуля, класса и теста. Как и в случае с приспособлениями py.test или unittest, установка всегда запускается перед любым тестом (или набором тестов для тестовых пакетов и модулей); teardown запускается, если установка завершилась успешно, независимо от статуса тестового запуска.

Модуль носа.tools предоставляет ряд средств тестирования, которые могут оказаться полезными, включая декораторы для ограничения времени выполнения теста и тестирования исключений, а также все те же методы assertX, которые есть в unittest.TestCase.

  • nose.tools.ok_(expr, msg = None) - Сокращение от assert.

  • nose.tools.eq_(a, b, msg = None) - Сокращение для 'assert a == b, «% r! =% R»% (a, b)

  • nose.tools.make_decorator(func) - Обертывает тестовый декоратор, чтобы правильно воспроизводить метаданные декорированной функции, включая дополнительные вещи носа (а именно настройку и разборку).

  • nose.tools.raises(*exceptions) - Для успешного прохождения теста необходимо вызвать одно из ожидаемых исключений.

  • nose.tools.timed(limit) - Тест должен закончиться в течение указанного срока, чтобы пройти

  • nose.tools.istest(func) - Декоратор, чтобы пометить функцию или метод как тест

  • nose.tools.nottest(func) - Декоратор для отметки функции или метода как не тестовых

Параметризованное тестирование

Среда тестирования Python, unittest, не имеет простого способа запуска параметризованных тестовых примеров. Другими словами, вы не можете легко передать аргументы вunittest.TestCase снаружи.

Однако порты модуля pytest тестируют параметризацию несколькими хорошо интегрированными способами:

  • pytest.fixture() позволяет определять параметризацию на уровне функций крепления.

  • @pytest.mark.parametrizeпозволяет определять параметризацию на уровне функции или класса. Он предоставляет несколько наборов аргументов / фикстур для конкретной тестовой функции или класса.

  • pytest_generate_tests позволяет реализовать вашу собственную схему динамической параметризации или расширения.

Сторонний модуль, «параметризованный», позволяет параметризованное тестирование с любой тестовой платформой Python. Его можно скачать по этой ссылке -https://github.com/wolever/nose-parameterized