Добавлены тесты для CoreCommand
This commit is contained in:
@@ -68,7 +68,14 @@ class CoreCommand(BaseCommand):
|
||||
:param length Общая длина
|
||||
"""
|
||||
|
||||
p_len = len(str(value)) + len(name) + 2
|
||||
points = "." * (length - p_len)
|
||||
if not name:
|
||||
p_len = length - len(str(value)) - 1
|
||||
else:
|
||||
p_len = length - len(str(value)) - len(name) - 2
|
||||
|
||||
print(f"{name} {points} {value}")
|
||||
if p_len <= 0:
|
||||
points = ""
|
||||
else:
|
||||
points = " " + ("." * p_len) + " "
|
||||
|
||||
print(f"{name}{points}{value}")
|
||||
|
||||
25
net/xeaf/rack/tests/core/_core_command_mocks.py
Normal file
25
net/xeaf/rack/tests/core/_core_command_mocks.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# DRF Rack
|
||||
# Библиотека классов расширений для Django REST Framework
|
||||
#
|
||||
# Автор: Николай В. Анохин <n.anokhin@xeaf.net>
|
||||
# Все права защищены. Лицензия: MIT
|
||||
|
||||
"""
|
||||
Описание mock-классов для тестов CoreCommand
|
||||
"""
|
||||
|
||||
from net.xeaf.rack.core import CoreCommand
|
||||
|
||||
|
||||
class TestCommand(CoreCommand):
|
||||
"""
|
||||
Тестовая реализация команды для проверки базовых методов вывода отчетов
|
||||
"""
|
||||
|
||||
def handle(self, *args, **options):
|
||||
"""
|
||||
Обязательный метод для Django BaseCommand
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# Все права защищены. Лицензия: MIT
|
||||
|
||||
"""
|
||||
Описание mock-классов для CoreEnumChoicesTests
|
||||
Описание mock-классов для тестов CoreEnum
|
||||
"""
|
||||
|
||||
from net.xeaf.rack.core import CoreEnum
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# DRF Rack
|
||||
# Библиотека классов расширений для Django REST Framework
|
||||
#
|
||||
# Автор: Николай В. Анохин <n.anokhin@xeaf.net>
|
||||
# Все права защищены. Лицензия: MIT
|
||||
|
||||
"""
|
||||
Описание класса CoreCommandClearDatabaseTests
|
||||
"""
|
||||
|
||||
from net.xeaf.rack.core.testing import CoreUserStoryTestCase
|
||||
from net.xeaf.rack.models.user_story import AccountTestData
|
||||
from ._core_command_mocks import TestCommand
|
||||
|
||||
|
||||
class CoreCommandClearDatabaseTests(CoreUserStoryTestCase):
|
||||
"""
|
||||
Тестовый класс для CoreCommand._clear_database()
|
||||
"""
|
||||
|
||||
def test_clear_database_removes_all_user_stories_from_db(self):
|
||||
"""
|
||||
Тест проверяет, что после вызова _clear_database известные объекты User Story удаляются из БД
|
||||
"""
|
||||
|
||||
# Arrange
|
||||
command_instance = TestCommand()
|
||||
|
||||
# Проверяем, что перед тестом база наполнена (Иванов существует в БД)
|
||||
ivanov_id = AccountTestData.IVANOV_ID
|
||||
account_model = AccountTestData.get_ivanov_account().__class__
|
||||
self.assertTrue(account_model.objects.filter(id=ivanov_id).exists())
|
||||
|
||||
# Act
|
||||
command_instance._clear_database()
|
||||
|
||||
# Assert
|
||||
# Проверяем реальное состояние БД: объектов больше быть не должно
|
||||
self.assertFalse(account_model.objects.filter(id=ivanov_id).exists())
|
||||
self.assertEqual(account_model.objects.count(), 0)
|
||||
177
net/xeaf/rack/tests/core/core_command_is_debug_or_test_tests.py
Normal file
177
net/xeaf/rack/tests/core/core_command_is_debug_or_test_tests.py
Normal file
@@ -0,0 +1,177 @@
|
||||
# DRF Rack
|
||||
# Библиотека классов расширений для Django REST Framework
|
||||
#
|
||||
# Автор: Николай В. Анохин <n.anokhin@xeaf.net>
|
||||
# Все права защищены. Лицензия: MIT
|
||||
|
||||
"""
|
||||
Описание класса CoreCommandIsDebugOrTestTests
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
from net.xeaf.rack.core import CoreCommand
|
||||
from net.xeaf.rack.core.testing import CoreSimpleTestCase
|
||||
|
||||
|
||||
class CoreCommandIsDebugOrTestTests(CoreSimpleTestCase):
|
||||
"""
|
||||
Тестовый класс для CoreCommand._is_debug_or_test()
|
||||
"""
|
||||
|
||||
def test_is_debug_or_test_returns_true_when_debug_enabled(self):
|
||||
"""
|
||||
Тест проверяет, что метод возвращает True при включенном DEBUG
|
||||
"""
|
||||
|
||||
# Arrange
|
||||
original_debug = settings.DEBUG
|
||||
settings.DEBUG = True
|
||||
original_argv = sys.argv.copy()
|
||||
|
||||
try:
|
||||
# Act
|
||||
result = CoreCommand._is_debug_or_test()
|
||||
|
||||
# Assert
|
||||
self.assertTrue(result)
|
||||
finally:
|
||||
# Cleanup
|
||||
settings.DEBUG = original_debug
|
||||
sys.argv = original_argv
|
||||
|
||||
def test_is_debug_or_test_returns_true_when_test_in_argv(self):
|
||||
"""
|
||||
Тест проверяет, что метод возвращает True, когда в аргументах командной строки присутствует 'test'
|
||||
"""
|
||||
|
||||
# Arrange
|
||||
original_debug = settings.DEBUG
|
||||
settings.DEBUG = False
|
||||
original_argv = sys.argv.copy()
|
||||
sys.argv = ['manage.py', 'test']
|
||||
|
||||
try:
|
||||
# Act
|
||||
result = CoreCommand._is_debug_or_test()
|
||||
|
||||
# Assert
|
||||
self.assertTrue(result)
|
||||
finally:
|
||||
# Cleanup
|
||||
settings.DEBUG = original_debug
|
||||
sys.argv = original_argv
|
||||
|
||||
def test_is_debug_or_test_returns_false_when_debug_disabled_and_test_not_in_argv(self):
|
||||
"""
|
||||
Тест проверяет, что метод возвращает False, когда DEBUG выключен и 'test' отсутствует в аргументах
|
||||
"""
|
||||
|
||||
# Arrange
|
||||
original_debug = settings.DEBUG
|
||||
settings.DEBUG = False
|
||||
original_argv = sys.argv.copy()
|
||||
sys.argv = ['manage.py', 'runserver']
|
||||
|
||||
try:
|
||||
# Act
|
||||
result = CoreCommand._is_debug_or_test()
|
||||
|
||||
# Assert
|
||||
self.assertFalse(result)
|
||||
finally:
|
||||
# Cleanup
|
||||
settings.DEBUG = original_debug
|
||||
sys.argv = original_argv
|
||||
|
||||
def test_is_debug_or_test_returns_true_when_debug_enabled_and_test_in_argv(self):
|
||||
"""
|
||||
Тест проверяет, что метод возвращает True, когда и DEBUG включен, и 'test' присутствует в аргументах
|
||||
"""
|
||||
|
||||
# Arrange
|
||||
original_debug = settings.DEBUG
|
||||
settings.DEBUG = True
|
||||
original_argv = sys.argv.copy()
|
||||
sys.argv = ['manage.py', 'test', '--verbosity=2']
|
||||
|
||||
try:
|
||||
# Act
|
||||
result = CoreCommand._is_debug_or_test()
|
||||
|
||||
# Assert
|
||||
self.assertTrue(result)
|
||||
finally:
|
||||
# Cleanup
|
||||
settings.DEBUG = original_debug
|
||||
sys.argv = original_argv
|
||||
|
||||
def test_is_debug_or_test_handles_test_substring_correctly(self):
|
||||
"""
|
||||
Тест проверяет, что метод правильно обрабатывает наличие подстроки 'test' в аргументах
|
||||
"""
|
||||
|
||||
# Arrange
|
||||
original_debug = settings.DEBUG
|
||||
settings.DEBUG = False
|
||||
original_argv = sys.argv.copy()
|
||||
sys.argv = ['manage.py', 'testing_tool']
|
||||
|
||||
try:
|
||||
# Act
|
||||
result = CoreCommand._is_debug_or_test()
|
||||
|
||||
# Assert
|
||||
# Метод должен проверять точное вхождение 'test', а не подстроку
|
||||
self.assertFalse(result)
|
||||
finally:
|
||||
# Cleanup
|
||||
settings.DEBUG = original_debug
|
||||
sys.argv = original_argv
|
||||
|
||||
def test_is_debug_or_test_returns_false_with_empty_argv(self):
|
||||
"""
|
||||
Тест проверяет поведение метода при пустом списке аргументов
|
||||
"""
|
||||
|
||||
# Arrange
|
||||
original_debug = settings.DEBUG
|
||||
settings.DEBUG = False
|
||||
original_argv = sys.argv.copy()
|
||||
sys.argv = []
|
||||
|
||||
try:
|
||||
# Act
|
||||
result = CoreCommand._is_debug_or_test()
|
||||
|
||||
# Assert
|
||||
self.assertFalse(result)
|
||||
finally:
|
||||
# Cleanup
|
||||
settings.DEBUG = original_debug
|
||||
sys.argv = original_argv
|
||||
|
||||
def test_is_debug_or_test_handles_nonexistent_settings_attribute(self):
|
||||
"""
|
||||
Тест проверяет, что метод корректно обрабатывает отсутствие атрибута DEBUG в настройках
|
||||
"""
|
||||
|
||||
# Arrange
|
||||
original_debug = getattr(settings, 'DEBUG', None)
|
||||
if hasattr(settings, 'DEBUG'):
|
||||
delattr(settings, 'DEBUG')
|
||||
original_argv = sys.argv.copy()
|
||||
sys.argv = ['manage.py', 'runserver']
|
||||
|
||||
try:
|
||||
# Act & Assert
|
||||
# В этом случае должно возникнуть исключение, так как settings.DEBUG отсутствует
|
||||
with self.assertRaises(AttributeError):
|
||||
CoreCommand._is_debug_or_test()
|
||||
finally:
|
||||
# Cleanup
|
||||
if original_debug is not None:
|
||||
settings.DEBUG = original_debug
|
||||
sys.argv = original_argv
|
||||
317
net/xeaf/rack/tests/core/core_command_report_int_value_tests.py
Normal file
317
net/xeaf/rack/tests/core/core_command_report_int_value_tests.py
Normal file
@@ -0,0 +1,317 @@
|
||||
# DRF Rack
|
||||
# Библиотека классов расширений для Django REST Framework
|
||||
#
|
||||
# Автор: Николай В. Анохин <n.anokhin@xeaf.net>
|
||||
# Все права защищены. Лицензия: MIT
|
||||
|
||||
"""
|
||||
Описание класса CoreCommandReportIntValueTests
|
||||
"""
|
||||
|
||||
import sys
|
||||
from io import StringIO
|
||||
|
||||
from net.xeaf.rack.core import CoreCommand
|
||||
from net.xeaf.rack.core.testing import CoreSimpleTestCase
|
||||
|
||||
|
||||
class CoreCommandReportIntValueTests(CoreSimpleTestCase):
|
||||
"""
|
||||
Тестовый класс для CoreCommand._report_int_value()
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
"""
|
||||
Подготовка тестовой среды: перехват stdout для проверки вывода
|
||||
"""
|
||||
|
||||
super().setUp()
|
||||
self.stdout_capture = StringIO()
|
||||
self.original_stdout = sys.stdout
|
||||
sys.stdout = self.stdout_capture
|
||||
|
||||
def tearDown(self):
|
||||
"""
|
||||
Восстановление stdout после каждого теста
|
||||
"""
|
||||
|
||||
sys.stdout = self.original_stdout
|
||||
super().tearDown()
|
||||
|
||||
def test_report_int_value_with_default_length(self):
|
||||
"""
|
||||
Тест проверяет вывод целочисленного значения с длиной по умолчанию
|
||||
"""
|
||||
|
||||
# Arrange
|
||||
name = "Total records"
|
||||
value = 42
|
||||
expected_length = 70
|
||||
|
||||
# Act
|
||||
CoreCommand._report_int_value(name, value)
|
||||
|
||||
# Assert
|
||||
output = self.stdout_capture.getvalue().strip()
|
||||
self.assertIn(name, output)
|
||||
self.assertIn(str(value), output)
|
||||
self.assertTrue(output.endswith(str(value)))
|
||||
# Проверяем, что общая длина строки соответствует ожидаемой
|
||||
# (без учета возможных пробелов в конце)
|
||||
self.assertEqual(len(output), expected_length)
|
||||
|
||||
def test_report_int_value_with_custom_length(self):
|
||||
"""
|
||||
Тест проверяет вывод целочисленного значения с пользовательской длиной
|
||||
"""
|
||||
|
||||
# Arrange
|
||||
name = "Count"
|
||||
value = 100
|
||||
custom_length = 50
|
||||
|
||||
# Act
|
||||
CoreCommand._report_int_value(name, value, custom_length)
|
||||
|
||||
# Assert
|
||||
output = self.stdout_capture.getvalue().strip()
|
||||
self.assertIn(name, output)
|
||||
self.assertIn(str(value), output)
|
||||
self.assertEqual(len(output), custom_length)
|
||||
|
||||
def test_report_int_value_with_small_value(self):
|
||||
"""
|
||||
Тест проверяет вывод маленького целочисленного значения
|
||||
"""
|
||||
|
||||
# Arrange
|
||||
name = "Errors"
|
||||
value = 0
|
||||
expected_length = 70
|
||||
|
||||
# Act
|
||||
CoreCommand._report_int_value(name, value)
|
||||
|
||||
# Assert
|
||||
output = self.stdout_capture.getvalue().strip()
|
||||
self.assertIn(name, output)
|
||||
self.assertIn("0", output)
|
||||
self.assertEqual(len(output), expected_length)
|
||||
|
||||
def test_report_int_value_with_large_value(self):
|
||||
"""
|
||||
Тест проверяет вывод большого целочисленного значения
|
||||
"""
|
||||
|
||||
# Arrange
|
||||
name = "Processed items"
|
||||
value = 1234567890
|
||||
expected_length = 70
|
||||
|
||||
# Act
|
||||
CoreCommand._report_int_value(name, value)
|
||||
|
||||
# Assert
|
||||
output = self.stdout_capture.getvalue().strip()
|
||||
self.assertIn(name, output)
|
||||
self.assertIn(str(value), output)
|
||||
self.assertEqual(len(output), expected_length)
|
||||
|
||||
def test_report_int_value_with_negative_value(self):
|
||||
"""
|
||||
Тест проверяет вывод отрицательного целочисленного значения
|
||||
"""
|
||||
|
||||
# Arrange
|
||||
name = "Balance"
|
||||
value = -50
|
||||
expected_length = 70
|
||||
|
||||
# Act
|
||||
CoreCommand._report_int_value(name, value)
|
||||
|
||||
# Assert
|
||||
output = self.stdout_capture.getvalue().strip()
|
||||
self.assertIn(name, output)
|
||||
self.assertIn("-50", output)
|
||||
self.assertEqual(len(output), expected_length)
|
||||
|
||||
def test_report_int_value_with_empty_name(self):
|
||||
"""
|
||||
Тест проверяет вывод значения с пустым названием
|
||||
"""
|
||||
|
||||
# Arrange
|
||||
name = ""
|
||||
value = 42
|
||||
expected_length = 70
|
||||
|
||||
# Act
|
||||
CoreCommand._report_int_value(name, value)
|
||||
|
||||
# Assert
|
||||
output = self.stdout_capture.getvalue().strip()
|
||||
self.assertIn(str(value), output)
|
||||
# При пустом имени будут только точки и значение
|
||||
self.assertTrue(output.startswith("."))
|
||||
self.assertEqual(len(output), expected_length)
|
||||
|
||||
def test_report_int_value_with_long_name(self):
|
||||
"""
|
||||
Тест проверяет вывод значения с длинным названием
|
||||
"""
|
||||
|
||||
# Arrange
|
||||
name = "This is a very long name that should be truncated or handled"
|
||||
value = 42
|
||||
expected_length = 70
|
||||
|
||||
# Act
|
||||
CoreCommand._report_int_value(name, value)
|
||||
|
||||
# Assert
|
||||
output = self.stdout_capture.getvalue().strip()
|
||||
self.assertIn(name, output)
|
||||
self.assertIn(str(value), output)
|
||||
self.assertEqual(len(output), expected_length)
|
||||
|
||||
def test_report_int_value_with_minimal_length(self):
|
||||
"""
|
||||
Тест проверяет вывод значения с минимальной длиной
|
||||
"""
|
||||
|
||||
# Arrange
|
||||
name = "X"
|
||||
value = 1
|
||||
minimal_length = 5 # Должно быть достаточно для "X ... 1"
|
||||
|
||||
# Act
|
||||
CoreCommand._report_int_value(name, value, minimal_length)
|
||||
|
||||
# Assert
|
||||
output = self.stdout_capture.getvalue().strip()
|
||||
self.assertIn(name, output)
|
||||
self.assertIn(str(value), output)
|
||||
self.assertEqual(len(output), minimal_length)
|
||||
|
||||
def test_report_int_value_with_length_smaller_than_needed(self):
|
||||
"""
|
||||
Тест проверяет поведение при длине меньше необходимой для отображения
|
||||
"""
|
||||
|
||||
# Arrange
|
||||
name = "Test"
|
||||
value = 12345
|
||||
too_small_length = 10
|
||||
|
||||
# Act
|
||||
CoreCommand._report_int_value(name, value, too_small_length)
|
||||
|
||||
# Assert
|
||||
output = self.stdout_capture.getvalue().strip()
|
||||
# Метод должен обработать ситуацию без ошибок
|
||||
# Возможно, обрежет название или значение
|
||||
self.assertIsInstance(output, str)
|
||||
self.assertLessEqual(len(output), too_small_length)
|
||||
|
||||
def test_report_int_value_with_zero_length(self):
|
||||
"""
|
||||
Тест проверяет поведение при нулевой длине
|
||||
"""
|
||||
|
||||
# Arrange
|
||||
name = "Test"
|
||||
value = 42
|
||||
zero_length = 0
|
||||
|
||||
# Act
|
||||
CoreCommand._report_int_value(name, value, zero_length)
|
||||
|
||||
# Assert
|
||||
output = self.stdout_capture.getvalue().strip()
|
||||
# При нулевой длине вывод должен быть пустым или минимальным
|
||||
self.assertIsInstance(output, str)
|
||||
|
||||
def test_report_int_value_format_with_dots(self):
|
||||
"""
|
||||
Тест проверяет, что между названием и значением выводятся точки
|
||||
"""
|
||||
|
||||
# Arrange
|
||||
name = "Records"
|
||||
value = 100
|
||||
|
||||
# Act
|
||||
CoreCommand._report_int_value(name, value)
|
||||
|
||||
# Assert
|
||||
output = self.stdout_capture.getvalue().strip()
|
||||
# Проверяем, что между названием и значением есть точки
|
||||
name_end_index = output.find(name) + len(name)
|
||||
value_start_index = output.rfind(str(value))
|
||||
middle_part = output[name_end_index:value_start_index]
|
||||
self.assertTrue(all(c == '.' for c in middle_part.replace(' ', '')))
|
||||
|
||||
def test_report_int_value_with_multiple_calls(self):
|
||||
"""
|
||||
Тест проверяет последовательный вывод нескольких значений
|
||||
"""
|
||||
|
||||
# Arrange
|
||||
test_data = [
|
||||
("First", 100),
|
||||
("Second", 200),
|
||||
("Third", 300)
|
||||
]
|
||||
|
||||
# Act
|
||||
for name, value in test_data:
|
||||
CoreCommand._report_int_value(name, value)
|
||||
|
||||
# Assert
|
||||
output = self.stdout_capture.getvalue()
|
||||
lines = output.strip().split('\n')
|
||||
self.assertEqual(len(lines), len(test_data))
|
||||
|
||||
for i, (name, value) in enumerate(test_data):
|
||||
self.assertIn(name, lines[i])
|
||||
self.assertIn(str(value), lines[i])
|
||||
self.assertEqual(len(lines[i]), 70)
|
||||
|
||||
def test_report_int_value_with_unicode_characters(self):
|
||||
"""
|
||||
Тест проверяет вывод значения с названием, содержащим Unicode-символы
|
||||
"""
|
||||
|
||||
# Arrange
|
||||
name = "Количество записей"
|
||||
value = 42
|
||||
expected_length = 70
|
||||
|
||||
# Act
|
||||
CoreCommand._report_int_value(name, value)
|
||||
|
||||
# Assert
|
||||
output = self.stdout_capture.getvalue().strip()
|
||||
self.assertIn(name, output)
|
||||
self.assertIn(str(value), output)
|
||||
self.assertEqual(len(output), expected_length)
|
||||
|
||||
def test_report_int_value_with_maximum_integer(self):
|
||||
"""
|
||||
Тест проверяет вывод максимального целочисленного значения
|
||||
"""
|
||||
|
||||
# Arrange
|
||||
name = "Max int"
|
||||
value = sys.maxsize
|
||||
expected_length = 70
|
||||
|
||||
# Act
|
||||
CoreCommand._report_int_value(name, value)
|
||||
|
||||
# Assert
|
||||
output = self.stdout_capture.getvalue().strip()
|
||||
self.assertIn(name, output)
|
||||
self.assertIn(str(value), output)
|
||||
self.assertEqual(len(output), expected_length)
|
||||
229
net/xeaf/rack/tests/core/core_command_report_separator_tests.py
Normal file
229
net/xeaf/rack/tests/core/core_command_report_separator_tests.py
Normal file
@@ -0,0 +1,229 @@
|
||||
# DRF Rack
|
||||
# Библиотека классов расширений для Django REST Framework
|
||||
#
|
||||
# Автор: Николай В. Анохин <n.anokhin@xeaf.net>
|
||||
# Все права защищены. Лицензия: MIT
|
||||
|
||||
"""
|
||||
Описание класса CoreCommandReportSeparatorTests
|
||||
"""
|
||||
|
||||
import sys
|
||||
from io import StringIO
|
||||
|
||||
from net.xeaf.rack.core import CoreCommand
|
||||
from net.xeaf.rack.core.testing import CoreSimpleTestCase
|
||||
|
||||
|
||||
class CoreCommandReportSeparatorTests(CoreSimpleTestCase):
|
||||
"""
|
||||
Тестовый класс для CoreCommand._report_separator()
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
"""
|
||||
Подготовка тестовой среды: перехват stdout для проверки вывода
|
||||
"""
|
||||
super().setUp()
|
||||
self.stdout_capture = StringIO()
|
||||
self.original_stdout = sys.stdout
|
||||
sys.stdout = self.stdout_capture
|
||||
|
||||
def tearDown(self):
|
||||
"""
|
||||
Восстановление stdout после каждого теста
|
||||
"""
|
||||
sys.stdout = self.original_stdout
|
||||
super().tearDown()
|
||||
|
||||
def test_report_separator_with_default_parameters(self):
|
||||
"""
|
||||
Тест проверяет вывод разделителя с параметрами по умолчанию
|
||||
"""
|
||||
# Arrange
|
||||
expected_length = 70
|
||||
expected_separator = '=' * expected_length
|
||||
|
||||
# Act
|
||||
CoreCommand._report_separator()
|
||||
|
||||
# Assert
|
||||
output = self.stdout_capture.getvalue()
|
||||
self.assertIn(expected_separator, output)
|
||||
self.assertEqual(output.count('\n'), 1) # Только одна строка с разделителем
|
||||
|
||||
def test_report_separator_with_custom_length(self):
|
||||
"""
|
||||
Тест проверяет вывод разделителя с пользовательской длиной
|
||||
"""
|
||||
# Arrange
|
||||
custom_length = 50
|
||||
expected_separator = '=' * custom_length
|
||||
|
||||
# Act
|
||||
CoreCommand._report_separator(length=custom_length)
|
||||
|
||||
# Assert
|
||||
output = self.stdout_capture.getvalue()
|
||||
self.assertIn(expected_separator, output)
|
||||
self.assertEqual(len(expected_separator), custom_length)
|
||||
|
||||
def test_report_separator_with_single_line(self):
|
||||
"""
|
||||
Тест проверяет вывод одинарного разделителя
|
||||
"""
|
||||
# Arrange
|
||||
expected_separator = '-' * 70
|
||||
|
||||
# Act
|
||||
CoreCommand._report_separator(double=False)
|
||||
|
||||
# Assert
|
||||
output = self.stdout_capture.getvalue()
|
||||
self.assertIn(expected_separator, output)
|
||||
self.assertNotIn('=' * 70, output)
|
||||
|
||||
def test_report_separator_with_double_line(self):
|
||||
"""
|
||||
Тест проверяет вывод двойного разделителя (поведение по умолчанию)
|
||||
"""
|
||||
# Arrange
|
||||
expected_separator = '=' * 70
|
||||
|
||||
# Act
|
||||
CoreCommand._report_separator(double=True)
|
||||
|
||||
# Assert
|
||||
output = self.stdout_capture.getvalue()
|
||||
self.assertIn(expected_separator, output)
|
||||
|
||||
def test_report_separator_with_first_new_line(self):
|
||||
"""
|
||||
Тест проверяет добавление пустой строки перед разделителем
|
||||
"""
|
||||
# Arrange
|
||||
expected_separator = '=' * 70
|
||||
|
||||
# Act
|
||||
CoreCommand._report_separator(first_new_line=True)
|
||||
|
||||
# Assert
|
||||
output = self.stdout_capture.getvalue()
|
||||
self.assertTrue(output.startswith('\n'))
|
||||
self.assertIn(expected_separator, output)
|
||||
|
||||
def test_report_separator_with_last_new_line(self):
|
||||
"""
|
||||
Тест проверяет добавление пустой строки после разделителя
|
||||
"""
|
||||
# Arrange
|
||||
expected_separator = '=' * 70
|
||||
|
||||
# Act
|
||||
CoreCommand._report_separator(last_new_line=True)
|
||||
|
||||
# Assert
|
||||
output = self.stdout_capture.getvalue()
|
||||
self.assertIn(expected_separator, output)
|
||||
self.assertTrue(output.endswith('\n'))
|
||||
|
||||
def test_report_separator_with_both_new_lines(self):
|
||||
"""
|
||||
Тест проверяет добавление пустых строк до и после разделителя
|
||||
"""
|
||||
# Arrange
|
||||
expected_separator = '=' * 70
|
||||
|
||||
# Act
|
||||
CoreCommand._report_separator(first_new_line=True, last_new_line=True)
|
||||
|
||||
# Assert
|
||||
output = self.stdout_capture.getvalue()
|
||||
self.assertTrue(output.startswith('\n'))
|
||||
self.assertTrue(output.endswith('\n'))
|
||||
self.assertIn(expected_separator, output)
|
||||
|
||||
def test_report_separator_with_minimal_length(self):
|
||||
"""
|
||||
Тест проверяет вывод разделителя минимальной длины
|
||||
"""
|
||||
# Arrange
|
||||
minimal_length = 1
|
||||
expected_separator = '=' * minimal_length
|
||||
|
||||
# Act
|
||||
CoreCommand._report_separator(length=minimal_length)
|
||||
|
||||
# Assert
|
||||
output = self.stdout_capture.getvalue()
|
||||
self.assertIn(expected_separator, output)
|
||||
self.assertEqual(len(expected_separator), minimal_length)
|
||||
|
||||
def test_report_separator_with_large_length(self):
|
||||
"""
|
||||
Тест проверяет вывод разделителя большой длины
|
||||
"""
|
||||
# Arrange
|
||||
large_length = 200
|
||||
expected_separator = '=' * large_length
|
||||
|
||||
# Act
|
||||
CoreCommand._report_separator(length=large_length)
|
||||
|
||||
# Assert
|
||||
output = self.stdout_capture.getvalue()
|
||||
self.assertIn(expected_separator, output)
|
||||
self.assertEqual(len(expected_separator), large_length)
|
||||
|
||||
def test_report_separator_combination_all_parameters(self):
|
||||
"""
|
||||
Тест проверяет комбинацию всех параметров
|
||||
"""
|
||||
# Arrange
|
||||
custom_length = 60
|
||||
expected_separator = '-' * custom_length
|
||||
|
||||
# Act
|
||||
CoreCommand._report_separator(
|
||||
length=custom_length,
|
||||
double=False,
|
||||
first_new_line=True,
|
||||
last_new_line=True
|
||||
)
|
||||
|
||||
# Assert
|
||||
output = self.stdout_capture.getvalue()
|
||||
self.assertTrue(output.startswith('\n'))
|
||||
self.assertTrue(output.endswith('\n'))
|
||||
self.assertIn(expected_separator, output)
|
||||
self.assertNotIn('=' * custom_length, output)
|
||||
|
||||
def test_report_separator_no_output_with_zero_length(self):
|
||||
"""
|
||||
Тест проверяет поведение при нулевой длине разделителя
|
||||
"""
|
||||
|
||||
# Act
|
||||
CoreCommand._report_separator(length=0)
|
||||
|
||||
# Assert
|
||||
output = self.stdout_capture.getvalue()
|
||||
# При длине 0 разделитель не выводится, но пустые строки могут быть
|
||||
self.assertNotIn('=' * 70, output)
|
||||
self.assertNotIn('-' * 70, output)
|
||||
|
||||
def test_report_separator_handles_negative_length(self):
|
||||
"""
|
||||
Тест проверяет поведение при отрицательной длине разделителя
|
||||
"""
|
||||
# Arrange
|
||||
negative_length = -10
|
||||
|
||||
# Act
|
||||
CoreCommand._report_separator(length=negative_length)
|
||||
|
||||
# Assert
|
||||
output = self.stdout_capture.getvalue()
|
||||
# Отрицательная длина вызовет ошибку или приведет к пустой строке
|
||||
# В зависимости от реализации, но метод должен отработать без ошибок
|
||||
self.assertIsInstance(output, str)
|
||||
@@ -42,11 +42,21 @@
|
||||
```
|
||||
Для конструктора паттерн аналогичен: `Тестовый класс для DemoClass.__init__()`.
|
||||
- Оформление тестовых методов: Докстринг внутри каждого тестового метода должен быть многострочным, оформленным с пустыми строками до и после текста.
|
||||
- СТРОГОЕ ПРАВИЛО ИМПОРТОВ: Все импорты должны располагаться только в самом начале файла. Импорты внутри классов или методов не допускаются.
|
||||
- Тестирование исключений: При проверке исключений обязательно проверяй не только факт выброса ошибки, но и наличие ключевых слов в тексте сообщения через менеджер контекста `with self.assertRaises(ValueError) as context:`.
|
||||
- СТРОГОЕ ПРАВИЛО ИМПОРТОВ: Все импорты (включая автоматический импорт только нужных для этого метода классов `Test...` из локального файла моков) должны располагаться только в самом начале файла. Импорты внутри классов или методов не допускаются.
|
||||
|
||||
- МЕТОДОЛОГИЯ AAA (Arrange, Act, Assert): Внутри тестовых методов код должен быть строго разделен на три логических блока с помощью комментариев `# Arrange`, `# Act` и `# Assert`. Покрывай как позитивные, так и негативные сценарии (invalid data, неавторизованный доступ, отсутствие прав, крайние состояния, деструктивные действия с данными, если применимо).
|
||||
|
||||
- ТЕСТИРОВАНИЕ ИСКЛЮЧЕНИЙ: При проверке исключений обязательно проверяй не только сам факт выброса ошибки, но и наличие ключевых слов в тексте сообщения об ошибке через менеджер контекста. Пример оформления:
|
||||
```python
|
||||
# Act & Assert
|
||||
with self.assertRaises(ValueError) as context:
|
||||
TestEmptyEnum.choices()
|
||||
self.assertIn("error message content", str(context.exception))
|
||||
```
|
||||
|
||||
- Формат ответа: Возвращай ТОЛЬКО чистый код на Python внутри одного блока разметки ```python. Без вводных фраз и пояснений после кода.
|
||||
|
||||
### АЛГОРИТМ ТВОЕЙ РАБОТЫ
|
||||
Пользователь пришлет тебе команду.
|
||||
- Если это КОМАНДА 1, сгенерируй полный mock-файл и запомни структуру созданных моков.
|
||||
- Если это КОМАНДА 2, проанализируй целевой метод (с учетом исключения для `__init__`), вспомни структуру моков из первого шага, автоматически выбери подходящие классы `Test...`, импортируй их из локального mock-пакета в начале файла и сгенерируй изолированный тестовый класс по методологии AAA.
|
||||
- Если это КОМАНДА 2, проанализируй целевой метод (с учетом исключения для `__init__`), вспомни структуру моков из первого шага, автоматически выбери подходящие классы `Test...`, импортируй их из локального mock-пакета в начале файла и сгенерируй изолированный тестовый класс, строго следуя методологии AAA и правилам проверки исключений.
|
||||
|
||||
@@ -49,6 +49,17 @@
|
||||
- Оформление вспомогательных/служебных классов (моков): Все вспомогательные классы для теста должны быть описаны в начале файла, строго ПОСЛЕ импортов, но ДО основного класса тестов. Описывать их внутри методов запрещено.
|
||||
- Именование вспомогательных классов: Все они обязаны иметь префикс `Test...` (например, `TestEnum`, `TestEmptyEnum`, `TestMockSerializer`). Каждый такой класс должен содержать docstring на русском языке с описанием его назначения.
|
||||
- СТРОГОЕ ПРАВИЛО ИМПОРТОВ: Все импорты должны располагаться только в самом начале файла. Импорты внутри классов или методов не допускаются.
|
||||
|
||||
- МЕТОДОЛОГИЯ AAA (Arrange, Act, Assert): Внутри тестовых методов код должен быть строго разделен на три логических блока с помощью комментариев `# Arrange`, `# Act` и `# Assert`. Покрывай как позитивные, так и негативные сценарии (invalid data, неавторизованный доступ, отсутствие прав, крайние состояния, деструктивные действия с данными, если применимо).
|
||||
|
||||
- ТЕСТИРОВАНИЕ ИСКЛЮЧЕНИЙ: При проверке исключений обязательно проверяй не только сам факт выброса ошибки, но и наличие ключевых слов в тексте сообщения об ошибке через менеджер контекста. Пример оформления:
|
||||
```python
|
||||
# Act & Assert
|
||||
with self.assertRaises(ValueError) as context:
|
||||
TestEmptyEnum.choices()
|
||||
self.assertIn("error message content", str(context.exception))
|
||||
```
|
||||
|
||||
- Тестирование исключений: При проверке исключений обязательно проверяй не только сам факт выброса ошибки, но и наличие ключевых слов в тексте сообщения об ошибке через менеджер контекста. Пример:
|
||||
```python
|
||||
with self.assertRaises(ValueError) as context:
|
||||
|
||||
Reference in New Issue
Block a user