From 785bf1ba29eab72a54aaba34e4ce99be8fbb4e15 Mon Sep 17 00:00:00 2001 From: "Nick V. Anokhin" Date: Sun, 19 Jul 2026 23:52:34 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20CoreEnum?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- net/xeaf/rack/core/core_enum.py | 34 ++++- net/xeaf/rack/tests/core/__init__.py | 6 + net/xeaf/rack/tests/core/_core_enum_mocks.py | 66 ++++++++++ .../core/core_enum_check_is_empty_tests.py | 52 ++++++++ .../tests/core/core_enum_choices_tests.py | 77 +++++++++++ .../tests/core/core_enum_from_string_tests.py | 123 ++++++++++++++++++ .../rack/tests/core/core_enum_keys_tests.py | 69 ++++++++++ .../rack/tests/core/core_enum_values_tests.py | 85 ++++++++++++ testing_2_llm.md | 50 +++++++ testing_llm.md | 61 +++++++++ 10 files changed, 622 insertions(+), 1 deletion(-) create mode 100644 net/xeaf/rack/tests/core/_core_enum_mocks.py create mode 100644 net/xeaf/rack/tests/core/core_enum_check_is_empty_tests.py create mode 100644 net/xeaf/rack/tests/core/core_enum_choices_tests.py create mode 100644 net/xeaf/rack/tests/core/core_enum_from_string_tests.py create mode 100644 net/xeaf/rack/tests/core/core_enum_keys_tests.py create mode 100644 net/xeaf/rack/tests/core/core_enum_values_tests.py create mode 100644 testing_2_llm.md create mode 100644 testing_llm.md diff --git a/net/xeaf/rack/core/core_enum.py b/net/xeaf/rack/core/core_enum.py index f94ea55..1498ba7 100644 --- a/net/xeaf/rack/core/core_enum.py +++ b/net/xeaf/rack/core/core_enum.py @@ -24,6 +24,7 @@ class CoreEnum(StrEnum): :return: Список для выбора значения """ + cls._check_is_empty() return [(item.value, item.name) for item in cls] @classmethod @@ -34,6 +35,7 @@ class CoreEnum(StrEnum): :return: Список ключей """ + cls._check_is_empty() return [item.name for item in cls] @classmethod @@ -44,4 +46,34 @@ class CoreEnum(StrEnum): :return: Список значений """ - return [item.value for item in cls] + cls._check_is_empty() + return [item.value for item in cls.__members__.values()] + + @classmethod + def _check_is_empty(cls): + """ + Проверяет, что перечисление не пустое + + :return: True, если перечисление не пустое + """ + + count = len(cls) + if count == 0: + raise ValueError(f"The {cls.__name__} enum must not be empty.") + + @classmethod + def from_string(cls, value: str) -> CoreEnum: + """ + Возвращает перечисление по строковому значению + + :param value: Строковое значение + + :return: Перечисление + """ + + for item in cls: + if item.value == value: + return item + + raise ValueError(f"The {cls.__name__} enum does not contain the value '{value}'") + diff --git a/net/xeaf/rack/tests/core/__init__.py b/net/xeaf/rack/tests/core/__init__.py index 74c23c5..809a448 100644 --- a/net/xeaf/rack/tests/core/__init__.py +++ b/net/xeaf/rack/tests/core/__init__.py @@ -7,3 +7,9 @@ """ Пакет описания тестов классов ядра """ + +from .core_enum_check_is_empty_tests import CoreEnumCheckIsEmptyTests +from .core_enum_choices_tests import CoreEnumChoicesTests +from .core_enum_from_string_tests import CoreEnumFromStringTests +from .core_enum_keys_tests import CoreEnumKeysTests +from .core_enum_values_tests import CoreEnumValuesTests diff --git a/net/xeaf/rack/tests/core/_core_enum_mocks.py b/net/xeaf/rack/tests/core/_core_enum_mocks.py new file mode 100644 index 0000000..bd97aec --- /dev/null +++ b/net/xeaf/rack/tests/core/_core_enum_mocks.py @@ -0,0 +1,66 @@ +# DRF Rack +# Библиотека классов расширений для Django REST Framework +# +# Автор: Николай В. Анохин +# Все права защищены. Лицензия: MIT + +""" +Описание mock-классов для CoreEnumChoicesTests +""" + +from net.xeaf.rack.core import CoreEnum + + +class TestEnum(CoreEnum): + """ + Тестовое перечисление для проверки методов choices, keys, values + """ + + OPTION1 = "value1" + OPTION2 = "value2" + OPTION3 = "value3" + + +class TestOrderedEnum(CoreEnum): + """ + Тестовое перечисление с упорядоченными элементами + """ + + FIRST = "first" + SECOND = "second" + THIRD = "third" + + +class TestDuplicateEnum(CoreEnum): + """ + Тестовое перечисление с дублирующимися значениями + """ + + ONE = "same" + TWO = "same" + THREE = "different" + + +class TestCaseEnum(CoreEnum): + """ + Тестовое перечисление с элементами разных регистров + """ + + LOW = "lower" + UPPER = "UPPER" + + +class TestSingleEnum(CoreEnum): + """ + Тестовое перечисление с одним элементом + """ + + ONLY = "only_value" + + +class TestEmptyEnum(CoreEnum): + """ + Пустое тестовое перечисление + """ + + pass diff --git a/net/xeaf/rack/tests/core/core_enum_check_is_empty_tests.py b/net/xeaf/rack/tests/core/core_enum_check_is_empty_tests.py new file mode 100644 index 0000000..ddc5759 --- /dev/null +++ b/net/xeaf/rack/tests/core/core_enum_check_is_empty_tests.py @@ -0,0 +1,52 @@ +# DRF Rack +# Библиотека классов расширений для Django REST Framework +# +# Автор: Николай В. Анохин +# Все права защищены. Лицензия: MIT + +""" +Описание класса CoreEnumCheckIsEmptyTests +""" + +from net.xeaf.rack.core.testing import CoreSimpleTestCase +from ._core_enum_mocks import TestEmptyEnum +from ._core_enum_mocks import TestEnum + + +class CoreEnumCheckIsEmptyTests(CoreSimpleTestCase): + """ + Тестовый класс для метода CoreEnum._check_is_empty() + """ + + def test_check_is_empty_with_non_empty_enum_does_not_raise_error(self): + """ + Тест проверяет, что _check_is_empty не выбрасывает исключение для непустого перечисления + """ + + # Act & Assert + try: + TestEnum._check_is_empty() + except ValueError: + self.fail("_check_is_empty raised ValueError unexpectedly for non-empty enum") + + def test_check_is_empty_with_empty_enum_raises_value_error(self): + """ + Тест проверяет, что _check_is_empty выбрасывает ValueError для пустого перечисления" + """ + + # Act & Assert + with self.assertRaises(ValueError) as context: + TestEmptyEnum._check_is_empty() + + self.assertIn("enum must not be empty", str(context.exception)) + + def test_check_is_empty_uses_correct_class_name_in_error(self): + """ + Тест проверяет, что в сообщении об ошибке используется правильное имя класса + """ + + # Act & Assert + with self.assertRaises(ValueError) as context: + TestEmptyEnum._check_is_empty() + + self.assertNotIn("CoreEnum", str(context.exception)) diff --git a/net/xeaf/rack/tests/core/core_enum_choices_tests.py b/net/xeaf/rack/tests/core/core_enum_choices_tests.py new file mode 100644 index 0000000..a798d2b --- /dev/null +++ b/net/xeaf/rack/tests/core/core_enum_choices_tests.py @@ -0,0 +1,77 @@ +# DRF Rack +# Библиотека классов расширений для Django REST Framework +# +# Автор: Николай В. Анохин +# Все права защищены. Лицензия: MIT + +""" +Описание класса CoreEnumChoicesTests +""" + +from net.xeaf.rack.core.testing import CoreSimpleTestCase +from ._core_enum_mocks import TestEmptyEnum +from ._core_enum_mocks import TestEnum +from ._core_enum_mocks import TestOrderedEnum +from ._core_enum_mocks import TestSingleEnum + + +class CoreEnumChoicesTests(CoreSimpleTestCase): + """ + Тестовый класс для CoreEnum.choices() + """ + + def test_choices_returns_list_of_tuples_with_value_and_name(self): + """ + Тест проверяет, что метод choices возвращает список кортежей (значение, имя) + """ + + # Arrange + expected = [("value1", "OPTION1"), ("value2", "OPTION2"), ("value3", "OPTION3")] + + # Act + result = TestEnum.choices() + + # Assert + self.assertEqual(result, expected) + self.assertIsInstance(result, list) + self.assertIsInstance(result[0], tuple) + self.assertEqual(len(result), 3) + + def test_choices_returns_empty_list_for_empty_enum(self): + """ + Тест проверяет, что для пустого перечисления метод choices выбрасывает исключение + """ + + # Act & Assert + with self.assertRaises(ValueError) as context: + TestEmptyEnum.choices() + + self.assertIn("enum must not be empty", str(context.exception)) + + def test_choices_preserves_enum_member_order(self): + """ + Тест проверяет сохранение порядка элементов перечисления + """ + + # Act + result = TestOrderedEnum.choices() + + # Assert + self.assertEqual(result[0], ("first", "FIRST")) + self.assertEqual(result[1], ("second", "SECOND")) + self.assertEqual(result[2], ("third", "THIRD")) + + def test_choices_handles_single_member_enum(self): + """ + Тест проверяет работу метода choices с перечислением из одного элемента + """ + + # Arrange + expected = [("only_value", "ONLY")] + + # Act + result = TestSingleEnum.choices() + + # Assert + self.assertEqual(result, expected) + self.assertEqual(len(result), 1) diff --git a/net/xeaf/rack/tests/core/core_enum_from_string_tests.py b/net/xeaf/rack/tests/core/core_enum_from_string_tests.py new file mode 100644 index 0000000..ea44de0 --- /dev/null +++ b/net/xeaf/rack/tests/core/core_enum_from_string_tests.py @@ -0,0 +1,123 @@ +# DRF Rack +# Библиотека классов расширений для Django REST Framework +# +# Автор: Николай В. Анохин +# Все права защищены. Лицензия: MIT + +""" +Описание класса CoreEnumFromStringTests +""" + +from net.xeaf.rack.core.testing import CoreSimpleTestCase +from ._core_enum_mocks import TestCaseEnum +from ._core_enum_mocks import TestDuplicateEnum +from ._core_enum_mocks import TestEmptyEnum +from ._core_enum_mocks import TestEnum +from ._core_enum_mocks import TestSingleEnum + + +class CoreEnumFromStringTests(CoreSimpleTestCase): + """ + Тестовый класс для CoreEnum.from_string() + """ + + def test_from_string_returns_correct_enum_member(self): + """ + Тест проверяет, что метод from_string возвращает корректный элемент перечисления + """ + + # Act + result = TestEnum.from_string("value2") + + # Assert + self.assertEqual(result, TestEnum.OPTION2) + self.assertEqual(result.value, "value2") + self.assertEqual(result.name, "OPTION2") + + def test_from_string_returns_first_matching_member_for_duplicate_values(self): + """ + Тест проверяет, что при дублирующихся значениях возвращается первый найденный элемент + """ + + # Act + result = TestDuplicateEnum.from_string("same") + + # Assert + self.assertEqual(result, TestDuplicateEnum.ONE) + self.assertEqual(result.value, "same") + self.assertEqual(result.name, "ONE") + + def test_from_string_raises_error_for_non_existent_value(self): + """ + Тест проверяет, что для несуществующего значения выбрасывается ValueError + """ + + # Act & Assert + with self.assertRaises(ValueError) as context: + TestEnum.from_string("non_existent_value") + + self.assertIn("enum does not contain the value 'non_existent_value'", str(context.exception)) + + def test_from_string_raises_error_for_empty_string(self): + """ + Тест проверяет, что для пустой строки выбрасывается ValueError + """ + + # Act & Assert + with self.assertRaises(ValueError) as context: + TestEnum.from_string("") + + self.assertIn("enum does not contain the value ''", str(context.exception)) + + def test_from_string_raises_error_for_empty_enum(self): + """ + Тест проверяет, что для пустого перечисления выбрасывается ValueError + """ + + # Act & Assert + with self.assertRaises(ValueError) as context: + TestEmptyEnum.from_string("any_value") + + self.assertIn("enum does not contain the value 'any_value'", str(context.exception)) + + def test_from_string_works_with_single_member_enum(self): + """ + Тест проверяет работу метода from_string с перечислением из одного элемента + """ + + # Act + result = TestSingleEnum.from_string("only_value") + + # Assert + self.assertEqual(result, TestSingleEnum.ONLY) + self.assertEqual(result.value, "only_value") + self.assertEqual(result.name, "ONLY") + + def test_from_string_case_sensitive_matching(self): + """ + Тест проверяет, что поиск значения чувствителен к регистру + """ + + # Act + result_lower = TestCaseEnum.from_string("lower") + result_upper = TestCaseEnum.from_string("UPPER") + + # Assert + self.assertEqual(result_lower, TestCaseEnum.LOW) + self.assertEqual(result_upper, TestCaseEnum.UPPER) + + # Проверяем, что поиск с другим регистром вызывает ошибку + with self.assertRaises(ValueError): + TestCaseEnum.from_string("Lower") + + def test_from_string_uses_correct_class_name_in_error(self): + """ + Тест проверяет, что в сообщении об ошибке используется правильное имя класса + """ + + # Act & Assert + with self.assertRaises(ValueError) as context: + TestEnum.from_string("wrong") + + self.assertIn("TestEnum", str(context.exception)) + self.assertNotIn("CoreEnum", str(context.exception)) diff --git a/net/xeaf/rack/tests/core/core_enum_keys_tests.py b/net/xeaf/rack/tests/core/core_enum_keys_tests.py new file mode 100644 index 0000000..d61ac04 --- /dev/null +++ b/net/xeaf/rack/tests/core/core_enum_keys_tests.py @@ -0,0 +1,69 @@ +# DRF Rack +# Библиотека классов расширений для Django REST Framework +# +# Автор: Николай В. Анохин +# Все права защищены. Лицензия: MIT + +""" +Описание класса CoreEnumKeysTests +""" + +from net.xeaf.rack.core.testing import CoreSimpleTestCase +from ._core_enum_mocks import TestEmptyEnum +from ._core_enum_mocks import TestEnum +from ._core_enum_mocks import TestOrderedEnum +from ._core_enum_mocks import TestSingleEnum + + +class CoreEnumKeysTests(CoreSimpleTestCase): + """ + Тестовый класс для CoreEnum.keys() + """ + + def test_keys_returns_list_of_enum_member_names(self): + """ + Тест проверяет, что метод keys возвращает список имен элементов перечисления + """ + + # Arrange + expected = ["OPTION1", "OPTION2", "OPTION3"] + + # Act + result = TestEnum.keys() + + # Assert + self.assertEqual(result, expected) + self.assertIsInstance(result, list) + self.assertEqual(len(result), 3) + + def test_keys_returns_empty_list_for_empty_enum(self): + """ + Тест проверяет, что для пустого перечисления метод keys выбрасывает исключение + """ + + # Act & Assert + with self.assertRaises(ValueError) as context: + TestEmptyEnum.keys() + self.assertIn("enum must not be empty", str(context.exception)) + + def test_keys_returns_names_in_definition_order(self): + """ + Тест проверяет, что метод keys возвращает имена в порядке объявления + """ + + # Act + result = TestOrderedEnum.keys() + + # Assert + self.assertEqual(result, ["FIRST", "SECOND", "THIRD"]) + + def test_keys_works_with_single_member_enum(self): + """ + Тест проверяет работу метода keys с перечислением из одного элемента + """ + + # Act + result = TestSingleEnum.keys() + + # Assert + self.assertEqual(result, ["ONLY"]) diff --git a/net/xeaf/rack/tests/core/core_enum_values_tests.py b/net/xeaf/rack/tests/core/core_enum_values_tests.py new file mode 100644 index 0000000..f0995ba --- /dev/null +++ b/net/xeaf/rack/tests/core/core_enum_values_tests.py @@ -0,0 +1,85 @@ +# DRF Rack +# Библиотека классов расширений для Django REST Framework +# +# Автор: Николай В. Анохин +# Все права защищены. Лицензия: MIT + +""" +Описание класса CoreEnumValuesTests +""" + +from net.xeaf.rack.core.testing import CoreSimpleTestCase +from ._core_enum_mocks import TestDuplicateEnum +from ._core_enum_mocks import TestEmptyEnum +from ._core_enum_mocks import TestEnum +from ._core_enum_mocks import TestOrderedEnum +from ._core_enum_mocks import TestSingleEnum + + +class CoreEnumValuesTests(CoreSimpleTestCase): + """ + Тестовый класс CoreEnum.values() + """ + + def test_values_returns_list_of_enum_member_values(self): + """ + Тест проверяет, что метод values возвращает список значений элементов перечисления + """ + + # Arrange + expected = ["value1", "value2", "value3"] + + # Act + result = TestEnum.values() + + # Assert + self.assertEqual(result, expected) + self.assertIsInstance(result, list) + self.assertEqual(len(result), 3) + + def test_values_returns_empty_list_for_empty_enum(self): + """ + Тест проверяет, что для пустого перечисления метод values выбрасывает исключение + """ + + # Act & Assert + with self.assertRaises(ValueError) as context: + TestEmptyEnum.values() + self.assertIn("enum must not be empty", str(context.exception)) + + def test_values_returns_values_in_definition_order(self): + """ + Тест проверяет, что метод values возвращает значения в порядке объявления + """ + + # Act + result = TestOrderedEnum.values() + + # Assert + self.assertEqual(result, ["first", "second", "third"]) + + def test_values_handles_duplicate_values_in_enum(self): + """ + Тест проверяет, что метод values корректно обрабатывает дублирующиеся значения + """ + + # Arrange + expected = ["same", "same", "different"] + + # Act + result = TestDuplicateEnum.values() + + # Assert + self.assertEqual(result, expected) + self.assertEqual(len(result), 3) + + def test_values_works_with_single_member_enum(self): + """ + Тест проверяет работу метода values с перечислением из одного элемента + """ + + # Act + result = TestSingleEnum.values() + + # Assert + self.assertEqual(result, ["only_value"]) diff --git a/testing_2_llm.md b/testing_2_llm.md new file mode 100644 index 0000000..d31a5b4 --- /dev/null +++ b/testing_2_llm.md @@ -0,0 +1,50 @@ +Ты — специализированный интерактивный ИИ-ассистент, эксперт по тестированию веб-приложений на Django и Django REST Framework (DRF) для библиотеки DRF-Rack (пакет `net.xeaf.rack`). + +Твоя задача — работать в режиме контекстного генератора по командам пользователя. После получения этого промпта ничего не генерируй, просто ответь: "Контекст DRF-Rack принят. Ожидаю исходный код класса." + +### РЕЖИМЫ РАБОТЫ И КОМАНДЫ ПОЛЬЗОВАТЕЛЯ +Ты должен строго переключать логику работы в зависимости от текстовой команды, которую пришлет пользователь вместе с кодом: + +--- +КОМАНДА 1: "сгенерировать mock-файл" +Твоя задача — проанализировать структуру предоставленного класса и создать для него ЕДИНЫЙ изолированный файл вспомогательных служебных классов и моков (Mocks), которые будут использоваться во всех последующих автотестах для этого класса. + +Правила для mock-файла: +1. Именование классов: Все сгенерированные служебные классы должны иметь префикс `Test...` (например, `TestEnum`, `TestEmptyEnum`). +2. Полнота сценариев: Создай моки для всех возможных состояний класса: дефолтное, пустое/граничное, упорядоченное, аномальное (если применимо). +3. Документирование: Каждый mock-класс обязан содержать docstring на русском языке с подробным описанием, для какого тестового сценария он предназначен. +4. Импорты: Все импорты базовых классов библиотеки должны располагаться только в самом начале файла. + +--- +КОМАНДА 2: "сгенерировать тесты для метода [НазваниеМетода]" +Твоя задача — сгенерировать код класса тестирования для ОДНОГО конкретного метода на основе ранее созданного mock-файла. + +Правила для файла тестов: +1. Изоляция: Один метод = Один тестовый класс = Один отдельный файл. +2. Именование класса теста: Строго по паттерну `[ИмяТестируемогоКласса][ИмяТестируемогоМетода]Tests`. +3. Зеркалирование структуры пакетов: Тесты находятся в пакете `net.xeaf.rack.tests`. Структура подпакетов тестов полностью зеркально повторяет структуру подпакетов исходного кода проекта. +4. Выбор базового класса (Предка): + - Если метод НЕ работает с БД, наследуйся от `CoreSimpleTestCase`. + - Если метод работает с БД, наследуйся от `CoreUserStoryTestCase`. + - Оба класса импортируются из пакета `net.xeaf.rack.core.testing`. +5. Изоляция БД: В тестах с БД используется SQLite в памяти (команда `call_command("rack_test_database")` внутри `CoreUserStoryTestCase.setUp()` автоматически сбрасывает и наполняет БД). База изолирована, данные можно изменять и удалять безболезненно. +6. АВТОМАТИЧЕСКИЙ ПОДБОР И ИСПОЛЬЗОВАНИЕ ВНЕШНИХ МОКОВ: Внутри тестового файла ЗАПРЕЩЕНО объявлять служебные или мок-классы. Так как ты уже генерировал mock-файл для этого класса на Шаге 1, ты должен САМОСТОЯТЕЛЬНО определить, какие из созданных тобой классов `Test...` необходимы для тестирования текущего метода (например, для позитивных сценариев, для тестов на пустоту, на упорядоченность и т.д.). Сформируй имя файла моков как `._[имя_тестируемого_файла_в_snake_case]_mocks` и автоматически пропиши импорт выбранных тобой служебных классов в самом начале файла. + +### ТРЕБОВАНИЯ К ЯЗЫКУ, ОФОРМЛЕНИЮ И СТИЛЮ КОДА (ДЛЯ ВСЕХ РЕЖИМОВ) +- Все комментарии и docstrings пишутся строго на русском языке. +- Оформление класса тестов: Докстринг главного класса тестов должен строго соответствовать паттерну: + ```python + class DemoClassDemoMethodTests(CoreSimpleTestCase): + """ + Тестовый класс для DemoClass.demo_method() + """ + ``` +- Оформление тестовых методов: Докстринг внутри каждого тестового метода должен быть многострочным, оформленным с пустыми строками до и после текста. +- СТРОГОЕ ПРАВИЛО ИМПОРТОВ: Все импорты (включая автоматический импорт только нужных для этого метода классов `Test...` из локального файла моков) должны располагаться только в самом начале файла. Импорты внутри классов или методов не допускаются. +- Тестирование исключений: При проверке исключений обязательно проверяй не только факт выброса ошибки, но и наличие ключевых слов в тексте сообщения через менеджер контекста `with self.assertRaises(ValueError) as context:`. +- Формат ответа: Возвращай ТОЛЬКО чистый код на Python внутри одного блока разметки ```python. Без вводных фраз и пояснений после кода. + +### АЛГОРИТМ ТВОЕЙ РАБОТЫ +Пользователь пришлет тебе команду. +- Если это КОМАНДА 1, сгенерируй полный mock-файл и запомни структуру созданных моков. +- Если это КОМАНДА 2, проанализируй целевой метод, вспомни структуру моков из первого шага, автоматически выбери подходящие классы `Test...`, импортируй их из локального mock-пакета в начале файла и сгенерируй изолированный тестовый класс по методологии AAA. diff --git a/testing_llm.md b/testing_llm.md new file mode 100644 index 0000000..08e4ab8 --- /dev/null +++ b/testing_llm.md @@ -0,0 +1,61 @@ +Ты — специализированный ИИ-ассистент, эксперт по тестированию веб-приложений на Django и Django REST Framework (DRF). +Твоя единственная задача — генерировать код класса тестирования для ОДНОГО конкретного метода предоставленного Python-класса, строго следуя внутренней архитектуре тестирования библиотеки DRF-Rack (пакет `net.xeaf.rack`). + +### АРХИТЕКТУРНЫЕ ПРАВИЛА И СТРУКТУРА ТЕСТОВ +1. Принцип изоляции: Один метод тестируемого класса = Один тестовый класс = Один отдельный файл. +2. Именование класса теста: Строго по паттерну `[ИмяТестируемогоКласса][ИмяТестируемогоМетода]Tests`. + - Пример: Для метода `DemoClass.demo_method()` класс тестов должен называться `DemoClassDemoMethodTests`. +3. Зеркалирование структуры пакетов: Тесты находятся в пакете `net.xeaf.rack.tests`. Структура подпакетов тестов полностью зеркально повторяет структуру подпакетов исходного кода проекта (обращай внимание на единственное/множественное число в названиях папок). + - Пример: Если тестируемый класс находится в `net.xeaf.rack.managers.ResponseManager`, то его тест-кейс должен располагаться в пакете `net.xeaf.rack.tests.manager.ResponseManagerDemoMethodTests`. +4. Выбор базового класса (Предка): + - Если метод НЕ работает с базой данных (чистая логика, сериализаторы без обращения к моделям, кастомные валидаторы), наследуйся от `CoreSimpleTestCase`. + - Если метод работает с БД (QuerySets, создание/удаление/обновление записей, ORM, Views), наследуйся от `CoreUserStoryTestCase`. + - ВАЖНО: Оба этих класса (`CoreSimpleTestCase` и `CoreUserStoryTestCase`) всегда импортируются из пакета `net.xeaf.rack.core.testing`. +5. Изоляция БД и свобода действий: В тестах с БД используется SQLite в памяти. Команда `call_command("rack_test_database")` внутри `CoreUserStoryTestCase.setUp()` автоматически полностью пересоздает структуру БД (миграции) и инициализирует дефолтных тестовых пользователей перед каждым тестом. + - ВАЖНО: База данных полностью изолирована для каждого отдельного теста. Ты можешь БЕЗБОЯЗНЕННО изменять, удалять или портить любые данные в БД (включая дефолтные аккаунты Иванова и Петрова) — это никак не повлияет на другие тесты. + +### СПРАВОЧНИК ИНФРАСТРУКТУРЫ ТЕСТИРОВАНИЯ (Доступные инструменты) +При генерации тестов ты должен использовать только существующие методы и свойства базовых классов: +1. Свойства классов: `self.factory` (Объект `APIRequestFactory`). +2. Методы создания запросов (возвращают DRF Request объект): + - `self.create_request(method, path, headers=None, data=None, query_params=None, auth=None)` + - `self.create_authenticated_request(method, path, headers=None, data=None, query_params=None, token=None)` +3. Готовые запросы от предопределенных пользователей (доступны ТОЛЬКО при наследовании от `CoreUserStoryTestCase`): + - `self.create_ivanov_request(method, path, headers=None, data=None, query_params=None)` + - `self.create_petrov_request(method, path, headers=None, data=None, query_params=None)` +4. Справочник тестовых данных (Используй для проверки привязок, ID и ORM-запросов): + - `AccountTestData.get_ivanov_account()` / `AccountTestData.get_petrov_account()` + - `AccountTestData.IVANOV_ID` / `AccountTestData.PETROV_ID` + - `SessionTestData.get_ivanov_session()` / `SessionTestData.get_petrov_session()` + - `SessionTestData.IVANOV_SESSION_TOKEN` / `SessionTestData.PETROV_SESSION_TOKEN` +5. Специфичные импорты проекта: Для HTTP-методов всегда используй энум `HttpMethod` (`HttpMethod.GET`, `HttpMethod.POST` и т.д.). + +### ТРЕБОВАНИЯ К ЯЗЫКУ, ОФОРМЛЕНИЮ И СТИЛЮ КОДА +- Все комментарии и docstrings в файле пишутся строго на русском языке. +- Оформление класса тестов: Докстринг главного класса тестов должен строго соответствовать паттерну: + ```python + class DemoClassDemoMethodTests(CoreSimpleTestCase): + """ + Тестовый класс для DemoClass.demo_method() + """ + ``` +- Оформление тестовых методов: Докстринг внутри каждого тестового метода должен быть многострочным, оформленным с пустыми строками до и после текста. Пример: + ```python + def test_some_case(self): + """ + Тест проверяет, что метод делает то-то и то-то + """ + ``` +- Оформление вспомогательных/служебных классов (моков): Все вспомогательные классы для теста должны быть описаны в начале файла, строго ПОСЛЕ импортов, но ДО основного класса тестов. Описывать их внутри методов запрещено. +- Именование вспомогательных классов: Все они обязаны иметь префикс `Test...` (например, `TestEnum`, `TestEmptyEnum`, `TestMockSerializer`). Каждый такой класс должен содержать docstring на русском языке с описанием его назначения. +- СТРОГОЕ ПРАВИЛО ИМПОРТОВ: Все импорты должны располагаться только в самом начале файла. Импорты внутри классов или методов не допускаются. +- Тестирование исключений: При проверке исключений обязательно проверяй не только сам факт выброса ошибки, но и наличие ключевых слов в тексте сообщения об ошибке через менеджер контекста. Пример: + ```python + with self.assertRaises(ValueError) as context: + TestEmptyEnum.choices() + self.assertIn("error message content", str(context.exception)) + ``` +- Формат ответа: Возвращай ТОЛЬКО чистый код на Python внутри одного блока разметки ```python. Без вводных фраз и пояснений. + +### АЛГОРИТМ ТВОЕЙ РАБОТЫ +Пользователь пришлет тебе код тестируемого класса с указанием пути к пакету и названия метода. Ты должен проанализировать его, выбрать правильного предка (`CoreSimpleTestCase` или `CoreUserStoryTestCase`), сгенерировать служебные классы с префиксом `Test...` и выдать готовый тестовый файл, строго соответствующий правилам оформления и кодстайлу.