Уважаемые слушатели! В этом видео я покажу вам чуть более серьезное тестирование при помощи библиотеки unittest. Допустим, у нас есть функция для вычисления чисел Фибоначчи, которая пока что специально не работает. И я хочу написать модульные тесты, то есть покрыть ее некоторыми тестами, достаточно полно этих тестов, может быть достаточно много. Каждый из тестов будет, собственно, вызовом метода. Для этого нужно создать модуль тестирующий, тестирующий модуль будет содержать тестирующий класс. Самое главное, что этот тестирующий класс должен наследоваться от unittest.TestCase. И тестирующими методами среди его методов будут все методы, которые начинаются со слова test. Достаточно написать какой-нибудь простенький тест, например, давайте, проверим, что число Фебоначчи от нуля — это ноль, я начну числа Фибоначчи от нуля считать. Можно добавить вот такой вот метод test_zero и он будет содержать в себе assertEcual. АssertEcual — это утверждение о том, что так должно быть проверяемое, соответственно, в классе TestCase модуль unittest автоматически запустит этот test_zero и оформит, красиво оформит результат, если тест будет заваливаться. Давайте, пока не будем проверять, потому что мы еще не написали в полное покрытие я набросаю еще несколько тестов и покажу еще варианты использования библиотеки unittest. В частности, если в вашем модуле достаточно много микротестов, как бы подслучаев, то, если у вас произойдет заваливание на одном подслучае, то у вас, по сути, весь этот маленький TestCase, он просто будет выброшен. А можно было бы протестировать их все, чтобы даже было видно, с каким номером это происходило. Это делается при помощи вызова функции "Subtest" с указанием некоторого индекса. Здесь я тестирую несколько чисел Фибоначчи, собственно, первые пять чисел Фибоначчи, такой простенький тест. И проверяю каждое n число Фибоначчи на равенство. Давайте, еще какое-нибудь число побольше введем и его тоже протестировали как отдельный TestCase. Test_positive какое-то положительное число. Надо сказать, когда производится анализ тестовых случаев, мы должны задуматься, а не могут ли нашу функцию вызвать с какими-то некорректными параметрами. Конечно же, когда мы ее уже напишем, нам не будет хотеться ее проверять на всякие совсем безумные случаи, мы будем проверять, ну, да, это для такого числа, это для такого вроде работает. А вот именно сейчас, когда функция еще не написана, но почему бы нет? Давайте, придеремся, как человек тестирующий программу, давайте, придеремся, например, что у нас для отрицательных чисел он должен по разработке через тестирование, мы сейчас заодно придумываем ее интерфейс, а что он должен сделать, если число дали отрицательное? Давайте, например, выбросим исключения. Скажем так, мы должны ожидать исключения. Библиотека unittest в этом случае позволяет перехватить это исключение и, самое главное, вам не придется об этом слишком много задумываться, никакого блока "Try" вам писать не придется. Просто берем и говорим, причем, я сделал это тоже с подслучаями, чтобы рассмотреть и, например, отрицательное число, и еще какое-нибудь, несколько отрицательных чисел, например, хотя бы, например, для минус один и для минус 10. В этом случае я ожидаю и утверждаю, что у меня будет исключение. Есть некоторое отличие первого случая и второго. Здесь я вызываю функцию самостоятельно, а здесь я передаю функцию и список ее аргументов. Естественным образом, поскольку методу "AssertRaises" потребуется, собственно, самому вызвать эту функцию, чтобы правильно окружить ее секции для отлавливания исключений. И, если исключение вызвано не будет, то это будет считаться ошибкой. Что еще? Допустим, такое же я сделаю для дробного типа, то есть, если сам тип не совпадает, тоже вставим такую проверку, и на этом тесты будем считать завершенными. Давайте, запустим и посмотрим, как наша функция прекрасно заваливается. Как видите, у нас целый тестовый отчет возникает в результате, где, что и почему завалилось. Причем с конкретными случаями, то есть, например, Test_fractional не вызвался not raised ArithmeticError. Да. Так, что у нас еще? Для десяти, соответственно, число Фибоначчи 10 не равно 55 и при этом мы видим еще и где именно это произошло. В частности, вот здесь мы видим, что в Test_simple пошли подслучаи первый, второй, третий, четвертый, пятый подслучай, в каждом из них мы видим отчет о том, что у нас произошло. В результате он сообщает, что, соответственно, пять тестов прошло и что 10 ошибок найдено. Анализ этих ошибок позволит найти необходимые поправки. Мы можем пытаться отремонтировать нашу функцию, как отремонтировать, по сути, написать ее, набросать быстренько, так, чтобы она прошла все тесты. Попытка сделать это каким-нибудь тривиальным способом, она может не пройти. То есть, если я в данном случае просто возьму и, давайте, методом динамического программирование так пробежимся, рекурсии совсем будет грустно. Вот таким вот образом я как крайний случай задаю ноль один, дальше заполняю все нулями, заготовляю и очередное число Фибоначчи равно сумме двух предыдущих. Все. Так вот, в результате при запуске тестирующего модуля, я поймаю, собственно, те самые ошибки list index out of range и не вызывается ArithmeticError. Что же, видите, для отрицательных чисел есть проблема и для float-чисел тоже есть проблема, test_fractional тоже валится. Остальные все тесты проходят, для этого я что сделаю? — Мне нужно дочинить функцию, после этого она будет соответствовать интерфейсу, то есть скажем так, модульное тестирование позволяет выполняемое заранее, до написания функции особенно, позволяет отловить всякие специфические случаи, потому что вы более придирчивы к тому коду, который еще не написан. Собственно, если добавить сюда проверку того, что у вас эта переменная нужного типа или если она отрицательная, например, то тогда вызываем арифметическую ошибку, после этого у меня все тесты прекрасно пройдут и я получу очень короткий и красивый отчет. Пять тестов прошли, ОК, тестирование завершено.