diff --git a/module12/MODULE_12.md b/module12/MODULE_12.md new file mode 100644 index 0000000..f3dab44 --- /dev/null +++ b/module12/MODULE_12.md @@ -0,0 +1,20 @@ +# Module 12: Supporting the development cycle + +## Module Description +This is module 12. + + +--- + +# TODO List + +- [x] Create a directory for module 12. +- [x] Create pull request from 'module12' branch to 'master' branch +- [x] Add homeworks + - [ ] Create a new branch from 'module12' branch + - [ ] Create a corresponding directory for the homework + - [ ] Add homework files to the directory + - [ ] Create a pull request from 'hw*' branch to 'module12' branch + - [ ] After checkup with instructor merge pull request +- [ ] Add homework descriptions to MODULE_12.md +- [ ] Merge pull request \ No newline at end of file diff --git a/module12/hw1/img.png b/module12/hw1/img.png new file mode 100644 index 0000000..d237ac2 Binary files /dev/null and b/module12/hw1/img.png differ diff --git a/module12/hw1/runner.py b/module12/hw1/runner.py new file mode 100644 index 0000000..a61a745 --- /dev/null +++ b/module12/hw1/runner.py @@ -0,0 +1,13 @@ +class Runner: + def __init__(self, name): + self.name = name + self.distance = 0 + + def run(self): + self.distance += 10 + + def walk(self): + self.distance += 5 + + def __str__(self): + return self.name diff --git a/module12/hw1/tests_12_1.py b/module12/hw1/tests_12_1.py new file mode 100644 index 0000000..987d571 --- /dev/null +++ b/module12/hw1/tests_12_1.py @@ -0,0 +1,73 @@ +# Домашнее задание по теме "Простые Юнит-Тесты" +""" +Задача "Проверка на выносливость": + +В первую очередь скачайте исходный код, который нужно обложить тестами с GitHub. (Можно скопировать) +В этом коде сможете обнаружить класс Runner, объекты которого вам будет необходимо протестировать. + +Напишите класс RunnerTest, наследуемый от TestCase из модуля unittest. В классе пропишите следующие методы: + 1. test_walk - метод, в котором создаётся объект класса Runner с произвольным именем. + Далее вызовите метод walk у этого объекта 10 раз. + После чего методом assertEqual сравните distance этого объекта со значением 50. + 2. test_run - метод, в котором создаётся объект класса Runner с произвольным именем. + Далее вызовите метод run у этого объекта 10 раз. + После чего методом assertEqual сравните distance этого объекта со значением 100. + 3. test_challenge - метод в котором создаются 2 объекта класса Runner с произвольными именами. + Далее 10 раз у объектов вызываются методы run и walk соответственно. + Т.к. дистанции должны быть разными, используйте метод assertNotEqual, чтобы убедится в неравенстве результатов. + +Запустите кейс RunnerTest. В конечном итоге все 3 теста должны пройти проверку. + +Пункты задачи: + 1. Скачайте исходный код для тестов. + 2. Создайте класс RunnerTest и соответствующие описанию методы. + 3. Запустите RunnerTest и убедитесь в правильности результатов. +""" +from module12.hw1.runner import Runner +import unittest + + +class RunnerTest(unittest.TestCase): + """ Тесты для класса Runner """ + + def test_walk(self): + # Создаем объект класса Runner + runner = Runner("TestRunner") + + # Вызываем метод walk 10 раз + for _ in range(10): + runner.walk() + + # Проверяем, что расстояние равно 50 + self.assertEqual(runner.distance, 50) + + + def test_run(self): + # Создаем объект класса Runner + runner = Runner("TestRunner") + + # Вызываем метод run 10 раз + for _ in range(10): + runner.run() + + # Проверяем, что расстояние равно 100 + self.assertEqual(runner.distance, 100) + + + def test_challenge(self): + # Создаем два объекта класса Runner + runner1 = Runner("Runner1") + runner2 = Runner("Runner2") + + # Runner1 бегает, Runner2 ходит + for _ in range(10): + runner1.run() + runner2.walk() + + # Проверяем, что дистанции разные + self.assertNotEqual(runner1.distance, runner2.distance) + + +# Запуск тестов +if __name__ == '__main__': + unittest.main() diff --git a/module12/hw2/img.png b/module12/hw2/img.png new file mode 100644 index 0000000..e607f56 Binary files /dev/null and b/module12/hw2/img.png differ diff --git a/module12/hw2/runner_and_tournament.py b/module12/hw2/runner_and_tournament.py new file mode 100644 index 0000000..9b73368 --- /dev/null +++ b/module12/hw2/runner_and_tournament.py @@ -0,0 +1,39 @@ +class Runner: + def __init__(self, name, speed=5): + self.name = name + self.distance = 0 + self.speed = speed + + def run(self): + self.distance += self.speed * 2 + + def walk(self): + self.distance += self.speed + + def __str__(self): + return self.name + + def __eq__(self, other): + if isinstance(other, str): + return self.name == other + elif isinstance(other, Runner): + return self.name == other.name + + +class Tournament: + def __init__(self, distance, *participants): + self.full_distance = distance + self.participants = list(participants) + + def start(self): + finishers = {} + place = 1 + while self.participants: + for participant in self.participants: + participant.run() + if participant.distance >= self.full_distance: + finishers[place] = participant + place += 1 + self.participants.remove(participant) + + return finishers \ No newline at end of file diff --git a/module12/hw2/tests_12_2.py b/module12/hw2/tests_12_2.py new file mode 100644 index 0000000..da83d46 --- /dev/null +++ b/module12/hw2/tests_12_2.py @@ -0,0 +1,99 @@ +# Домашнее задание по теме "Методы Юнит-тестирования" +""" +Задача: +В первую очередь скачайте исходный код, который нужно обложить тестами с GitHub. (Можно скопировать) +В этом коде сможете обнаружить дополненный с предыдущей задачи класс Runner и новый класс Tournament. +Изменения в классе Runner: +Появился атрибут speed для определения скорости бегуна. +Метод __eq__ для сравнивания имён бегунов. +Переопределены методы run и walk, теперь изменение дистанции зависит от скорости. +Класс Tournament представляет собой класс соревнований, где есть дистанция, которую нужно пробежать и список участников. Также присутствует метод start, который реализует логику бега по предложенной дистанции. + +Напишите класс TournamentTest, наследованный от TestCase. В нём реализуйте следующие методы: + +setUpClass - метод, где создаётся атрибут класса all_results. Это словарь в который будут сохраняться результаты всех тестов. +setUp - метод, где создаются 3 объекта: +Бегун по имени Усэйн, со скоростью 10. +Бегун по имени Андрей, со скоростью 9. +Бегун по имени Ник, со скоростью 3. +tearDownClass - метод, где выводятся all_results по очереди в столбец. + +Так же методы тестирования забегов, в которых создаётся объект Tournament на дистанцию 90. У объекта класса Tournament запускается метод start, который возвращает словарь в переменную all_results. В конце вызывается метод assertTrue, в котором сравниваются последний объект из all_results (брать по наибольшему ключу) и предполагаемое имя последнего бегуна. +Напишите 3 таких метода, где в забегах участвуют (порядок передачи в объект Tournament соблюсти): +Усэйн и Ник +Андрей и Ник +Усэйн, Андрей и Ник. +Как можно понять: Ник всегда должен быть последним. + +Дополнительно (не обязательно, не влияет на зачёт): +В данной задаче, а именно в методе start класса Tournament, допущена логическая ошибка. В результате его работы бегун с меньшей скоростью может пробежать некоторые дистанции быстрее, чем бегун с большей. +Попробуйте решить эту проблему и обложить дополнительными тестами. +""" +import unittest +from module12.hw2.runner_and_tournament import Runner, Tournament + + +class TournamentTest(unittest.TestCase): + + + @classmethod + def setUpClass(cls): + # Создаем атрибут для хранения результатов всех тестов + cls.all_results = {} + + + def setUp(self): + # Создаем объекты бегунов + self.usain = Runner("Усэйн", 10) + self.andrey = Runner("Андрей", 9) + self.nick = Runner("Ник", 3) + + + @classmethod + def tearDownClass(cls): + # Выводим результаты всех тестов после их завершения + for test_name, result in cls.all_results.items(): + # Используем имена бегунов для отображения результатов + finishers = {place: str(participant) for place, participant in result.items()} + print(f"{test_name}: {finishers}") + + + def test_tournament_usain_and_nick(self): + # Создаем объект Tournament для Усэйна и Ника + tournament = Tournament(90, self.usain, self.nick) + results = tournament.start() + + # Сохраняем результаты в all_results + TournamentTest.all_results["Усэйн и Ник"] = results + + # Проверяем, что Ник последний + self.assertTrue(results[max(results.keys())] == self.nick) + + + def test_tournament_andrey_and_nick(self): + # Создаем объект Tournament для Андрея и Ника + tournament = Tournament(90, self.andrey, self.nick) + results = tournament.start() + + # Сохраняем результаты в all_results + TournamentTest.all_results["Андрей и Ник"] = results + + # Проверяем, что Ник последний + self.assertTrue(results[max(results.keys())] == self.nick) + + + def test_tournament_usain_andrey_and_nick(self): + # Создаем объект Tournament для Усэйна, Андрея и Ника + tournament = Tournament(90, self.usain, self.andrey, self.nick) + results = tournament.start() + + # Сохраняем результаты в all_results + TournamentTest.all_results["Усэйн, Андрей и Ник"] = results + + # Проверяем, что Ник последний + self.assertTrue(results[max(results.keys())] == self.nick) + + +# Запуск тестов +if __name__ == '__main__': + unittest.main() diff --git a/module12/hw4/img.png b/module12/hw4/img.png new file mode 100644 index 0000000..12f0fd1 Binary files /dev/null and b/module12/hw4/img.png differ diff --git a/module12/hw4/img_1.png b/module12/hw4/img_1.png new file mode 100644 index 0000000..40ec836 Binary files /dev/null and b/module12/hw4/img_1.png differ diff --git a/module12/hw4/rt_with_exceptions.py b/module12/hw4/rt_with_exceptions.py new file mode 100644 index 0000000..7bfbcc6 --- /dev/null +++ b/module12/hw4/rt_with_exceptions.py @@ -0,0 +1,56 @@ +class Runner: + def __init__(self, name, speed=5): + if isinstance(name, str): + self.name = name + else: + raise TypeError(f'Имя может быть только строкой, передано {type(name).__name__}') + self.distance = 0 + if speed > 0: + self.speed = speed + else: + raise ValueError(f'Скорость не может быть отрицательной, сейчас {speed}') + + def run(self): + self.distance += self.speed * 2 + + def walk(self): + self.distance += self.speed + + def __str__(self): + return self.name + + def __repr__(self): + return self.name + + def __eq__(self, other): + if isinstance(other, str): + return self.name == other + elif isinstance(other, Runner): + return self.name == other.name + + +class Tournament: + def __init__(self, distance, *participants): + self.full_distance = distance + self.participants = list(participants) + + def start(self): + finishers = {} + place = 1 + while self.participants: + for participant in self.participants: + participant.run() + if participant.distance >= self.full_distance: + finishers[place] = participant + place += 1 + self.participants.remove(participant) + + return finishers + + +# first = Runner('Вося', 10) +# second = Runner('Илья', 5) +# # third = Runner('Арсен', 10) +# +# t = Tournament(101, first, second) +# print(t.start()) \ No newline at end of file diff --git a/module12/hw4/runner_tests.log b/module12/hw4/runner_tests.log new file mode 100644 index 0000000..db2bfb0 --- /dev/null +++ b/module12/hw4/runner_tests.log @@ -0,0 +1,16 @@ +WARNING: Неверный тип данных для объекта Runner: Имя может быть только строкой, передано int +Traceback (most recent call last): + File "C:\Users\daire\PycharmProjects\python-course\module12\hw3\tests_12_4.py", line 78, in test_run + runner = Runner(12345, speed=10) # Это вызовет исключение + ^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\daire\PycharmProjects\python-course\module12\hw3\rt_with_exceptions.py", line 6, in __init__ + raise TypeError(f'Имя может быть только строкой, передано {type(name).__name__}') +TypeError: Имя может быть только строкой, передано int +WARNING: Неверная скорость для Runner: Скорость не может быть отрицательной, сейчас -5 +Traceback (most recent call last): + File "C:\Users\daire\PycharmProjects\python-course\module12\hw3\tests_12_4.py", line 61, in test_walk + runner = Runner("TestRunner", speed=-5) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\daire\PycharmProjects\python-course\module12\hw3\rt_with_exceptions.py", line 11, in __init__ + raise ValueError(f'Скорость не может быть отрицательной, сейчас {speed}') +ValueError: Скорость не может быть отрицательной, сейчас -5 diff --git a/module12/hw4/tests_12_4.py b/module12/hw4/tests_12_4.py new file mode 100644 index 0000000..3b66a10 --- /dev/null +++ b/module12/hw4/tests_12_4.py @@ -0,0 +1,94 @@ +# +""" +Задача "Логирование бегунов": +В первую очередь скачайте исходный код, который нужно обложить тестами с GitHub. (Можно скопировать) +Основное обновление - выбрасывание исключений, если передан неверный тип в name и если передано отрицательное значение в speed. + +Для решения этой задачи вам понадобиться класс RunnerTest из предыдущей задачи. +В модуле tests_12_4.py импортируйте пакет logging и настройте basicConfig на следующие параметры: +Уровень - INFO +Режим - запись с заменой('w') +Название файла - runner_tests.log +Кодировка - UTF-8 +Формат вывода - на своё усмотрение, обязательная информация: уровень логирования, сообщение логирования. + +Дополните методы тестирования в классе RunnerTest следующим образом: +test_walk: +Оберните основной код конструкцией try-except. +При создании объекта Runner передавайте отрицательное значение в speed. +В блок try добавьте логирование INFO с сообщением '"test_walk" выполнен успешно' +В блоке except обработайте исключение соответствующего типа и логируйте его на уровне WARNING с сообщением "Неверная скорость для Runner". +test_run: +Оберните основной код конструкцией try-except. +При создании объекта Runner передавайте что-то кроме строки в name. +В блок try добавьте логирование INFO с сообщением '"test_run" выполнен успешно' +В блоке except обработайте исключение соответствующего типа и логируйте его на уровне WARNING с сообщением "Неверный тип данных для объекта Runner". +""" +import unittest +import logging +from rt_with_exceptions import Runner + + +# Настройка логирования +logging.basicConfig( + level=logging.INFO, + filename='runner_tests.log', + filemode='w', + encoding='utf-8', + format='%(levelname)s: %(message)s' +) + + +# Декоратор для пропуска тестов, если is_frozen = True +def skip_if_frozen(func): + def wrapper(self, *args, **kwargs): + if getattr(self, 'is_frozen', False): + self.skipTest('Тесты в этом кейсе заморожены') + return func(self, *args, **kwargs) + return wrapper + + +class RunnerTest(unittest.TestCase): + """ Тесты для класса Runner """ + + is_frozen = False # Эти тесты должны выполняться + + + @skip_if_frozen + def test_walk(self): + try: + # Создаем объект класса Runner с отрицательной скоростью, что вызовет исключение + runner = Runner("TestRunner", speed=-5) + # Вызываем метод walk 10 раз + for _ in range(10): + runner.walk() + + # Логируем успешное выполнение теста + logging.info('"test_walk" выполнен успешно') + + except ValueError as e: + # Логируем исключение + logging.warning(f"Неверная скорость для Runner: {e}", exc_info=True) + + + @skip_if_frozen + def test_run(self): + try: + # Создаем объект класса Runner с неверным типом имени + runner = Runner(12345, speed=10) # Это вызовет исключение + + # Вызываем метод run 10 раз + for _ in range(10): + runner.run() + + # Логируем успешное выполнение теста + logging.info('"test_run" выполнен успешно') + + except TypeError as e: + # Логируем исключение + logging.warning(f"Неверный тип данных для объекта Runner: {e}", exc_info=True) + + +# Запуск тестов +if __name__ == '__main__': + unittest.main()