К основному содержанию
правило

unittest — правило для Cursor: как писать тесты на Python

Правило задаёт агенту стандарт оформления тестов на unittest: структура каталогов, имена классов и методов, ассерты, моки.

Установить в Cursor · Вручную: положить файлы Все способы и платформы ↓
.cursor/rules/unittest.mdc
Открыть на GitHub

Что делает unittest

Правило подключается к Cursor и действует на все файлы **/*.py. Оно описывает, как раскладывать тесты: отдельный каталог tests/, повторяющий структуру модулей приложения, файлы вида test_users.py, классы с префиксом Test, наследующие unittest.TestCase, методы с префиксом test_ и понятным описанием сценария.

Дальше идут требования к ассертам и фикстурам. Один тест проверяет один логический результат, для проверок берутся конкретные методы вроде assertIn вместо общих assertTrue. setUp и tearDown готовят и убирают состояние перед каждым методом, setUpClass и tearDownClass — один раз на класс для дорогих общих ресурсов. Внешние зависимости заменяются через MagicMock и @patch, причём правило прямо запрещает мокать внутреннюю логику самого тестируемого объекта.

Правило привязано к Python-проектам на unittest: если у вас pytest или тестов на Python нет, оно просто не сработает. Файл кладут вручную по пути .cursor/rules/unittest.mdc.

Какие задачи решает

  • разложить тесты по каталогам в соответствии со структурой модулей
  • дать тестовым классам и методам имена, которые находит автодискавери
  • разделить один тест на проверку одного результата
  • заменить общие assertTrue на конкретные методы проверки
  • вынести дорогой общий ресурс в setUpClass вместо setUp

Примеры запросов агенту

  • Напиши тесты для модуля users.py по правилу unittest: класс TestUserService, отдельные методы на каждый сценарий
  • Отрефактори тест: разбей проверки на отдельные методы и замени assertTrue на assertIn
  • Замокай внешний вызов через @patch, внутреннюю логику сервиса не трогай

Как установить unittest

Вручную: положить файлы

.cursor/rules/unittest.mdc

Во frontmatter: description, globs, alwaysApply

По шагам, с командами для каждой платформы: Cursor rules: файлы .mdc, четыре режима и замена .cursorrules

Из того же набора69

zod Правило для Cursor задаёт стандарты работы с Zod: строгий режим TypeScript, вывод типов из схем и проверка данных на входе. ★ 3 579звёзд репо vitest Правило задаёт Cursor, как писать юнит- и интеграционные тесты на Vitest: где держать файлы, как изолировать кейсы и мокать модули. ★ 3 579звёзд репо vercel Правило для Cursor с набором рекомендаций по разработке и деплою приложений на Vercel. Пригодится, если агент пишет код для Next.js и вы хотите, чтобы он сразу держал в голове конвенции платформы. ★ 3 579звёзд репо transformers Правило для Cursor задаёт стиль работы с библиотекой 🤗 Transformers: модульные модели, типизация, Trainer вместо ручных циклов обучения. ★ 3 579звёзд репо tornado Правило для Cursor задаёт стиль кода в Tornado: только async/await для ввода-вывода, полные аннотации типов и один обработчик ошибок на всё приложение. ★ 3 579звёзд репо three-js Правило для Cursor задаёт стандарты разработки на three.js: обработка ошибок WebGL, ленивая загрузка ассетов, оптимизация цикла рендера и освобождение ресурсов. ★ 3 579звёзд репо svelte Правило для Cursor задаёт, как писать компоненты Svelte 5: руны вместо старой реактивности, типизация и ключи в списках. Пригодится, если проект уже на Svelte 5. ★ 3 579звёзд репо streamlit Правило для Cursor задаёт, как писать приложения на Streamlit: кэшировать тяжёлые операции, держать UI отдельно от логики и разбивать проект на модули. ★ 3 579звёзд репо

Похожие

python-testing-patterns Seth Hobson Скилл помогает писать тесты Python с pytest, фикстурами и моками. Подходит для настройки тестового набора и отладки падающих проверок. CX Codex 36 943установок pytest-skill TestMu AI Скилл для ИИ-агентов, который пишет тесты pytest: фикстуры, parametrize, маркеры, мокинг и conftest. Пригодится, когда нужно покрыть Python-код тестами без ручной возни. CX Codex +1 412установок python-testing affaan-m Скилл задаёт подход к тестам Python на pytest: TDD, фикстуры, моки, параметризацию и проверку покрытия. Пригодится при создании и ревью тестов. CX Codex +1 4 900установок vitest-testing secondsky Скилл для написания юнит- и интеграционных тестов на Vitest в проектах на TypeScript и JavaScript. Пригодится, когда нужно быстро настроить конфиг, моки и покрытие. CX Codex +1 1 200установок Python Unit Test Generator — Comprehensive, Coverage-Mapped & Production-Ready sivasaiyadav8143 Промпт превращает кусок Python-кода в готовый набор юнит-тестов на pytest с картой покрытия и моками внешних зависимостей. GP ChatGPT ★ 174 597звёзд репо vitest pproenca Скилл даёт ИИ-агенту 44 правила для написания, отладки и ускорения тестов на Vitest. Помогает настроить моки, изолировать окружение и разобрать нестабильные проверки. CX Codex +1 6 100установок

Рядом в теме «Тесты и QA»

Всё по теме «Тесты и QA» →

Вопросы о unittest

Как установить правило unittest в Cursor?

Создайте файл .cursor/rules/unittest.mdc в корне проекта и вставьте в него содержимое правила.

Что делает правило unittest?

Задаёт агенту соглашения о тестах на Python: имена файлов, классов и методов, один логический ассерт на тест, фикстуры setUp/tearDown и работу с моками через unittest.mock.

На какие файлы действует правило?

На все файлы **/*.py — это указано в globs.

Исходный текст

unittest.mdc · CC0-1.0
---
description: Definitive guidelines for writing robust, maintainable, and idiomatic `unittest` tests in Python. Focuses on structure, naming, assertions, mocking, and performance.
globs: **/*.py
---
# unittest Best Practices

This guide establishes the definitive best practices for writing `unittest` tests in Python. Adhering to these rules ensures our test suite is fast, reliable, readable, and maintainable, integrating seamlessly into our CI/CD pipeline.

## 1. Code Organization and Structure

Organize tests logically within a dedicated `tests/` directory, mirroring your application's module structure.

### Test File Naming
Name test files clearly to enable automatic discovery and indicate their purpose.

❌ BAD:
```python
# my_app/tests/users.py
# my_app/tests/test_user_logic.py
```

✅ GOOD:
```python
# my_app/tests/test_users.py
# my_app/tests/test_auth_service.py
```

### Test Class Naming
All test classes *must* inherit from `unittest.TestCase` and start with `Test`.

❌ BAD:
```python
import unittest

class UserServiceTests(unittest.TestCase):
    # ...
```

✅ GOOD:
```python
import unittest

class TestUserService(unittest.TestCase):
    # ...
```

### Test Method Naming
Each test method *must* start with `test_` and describe the specific scenario and expected outcome.

❌ BAD:
```python
class TestUserService(unittest.TestCase):
    def create_user(self): # Not a test method, but might be mistaken for one
        pass
    def test_valid_user(self): # Vague
        pass
```

✅ GOOD:
```python
class TestUserService(unittest.TestCase):
    def test_create_user_with_valid_data_returns_user_object(self):
        pass
    def test_create_user_with_existing_email_raises_value_error(self):
        pass
```

### Running Tests
Always include the standard `if __name__ == '__main__':` block for direct execution and discovery.

```python
import unittest

class TestExample(unittest.TestCase):
    def test_something(self) -> None:
        self.assertTrue(True)

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

## 2. Assertions: Single Logical Assertion

Each test method should focus on verifying *one logical outcome*. This makes tests easier to understand and debug.

❌ BAD:
```python
class TestCalculator(unittest.TestCase):
    def test_add_and_subtract(self) -> None:
        calc = Calculator()
        self.assertEqual(calc.add(2, 3), 5)
        self.assertEqual(calc.subtract(5, 2), 3) # Tests two distinct things
```

✅ GOOD:
```python
class TestCalculator(unittest.TestCase):
    def test_add_returns_correct_sum(self) -> None:
        calc = Calculator()
        self.assertEqual(calc.add(2, 3), 5)

    def test_subtract_returns_correct_difference(self) -> None:
        calc = Calculator()
        self.assertEqual(calc.subtract(5, 2), 3)
```

### Use Specific Assert Methods
Leverage `unittest`'s rich set of assert methods for clarity and better error messages.

❌ BAD:
```python
class TestUser(unittest.TestCase):
    def test_user_is_active(self) -> None:
        user = User(active=True)
        self.assertTrue(user.active == True, "User should be active") # Redundant comparison
        self.assertTrue(user.name in ["Alice", "Bob"]) # Generic, less informative error
```

✅ GOOD:
```python
class TestUser(unittest.TestCase):
    def test_user_is_active(self) -> None:
        user = User(active=True)
        self.assertTrue(user.active) # Direct assertion

    def test_user_name_is_in_allowed_list(self) -> None:
        user = User(name="Alice")
        self.assertIn(user.name, ["Alice", "Bob"]) # Specific for membership
```

## 3. Fixtures (`setUp`/`tearDown`)

Use fixtures to establish a clean, isolated state for tests.

### `setUp` and `tearDown` (Per Test Method)
Use `setUp` to prepare resources *before each test method* and `tearDown` to clean up *after each test method*.

```python
import unittest
from unittest.mock import MagicMock

class TestDatabaseOperations(unittest.TestCase):
    def setUp(self) -> None:
        self.db_connection = MagicMock() # Mock a DB connection
        self.db_connection.create_table("users")

    def tearDown(self) -> None:
        self.db_connection.drop_table("users")
        self.db_connection.close()

    def test_add_user_to_db(self) -> None:
        self.db_connection.insert("users", {"name": "Alice"})
        self.db_connection.insert.assert_called_once_with("users", {"name": "Alice"})
```

### `setUpClass` and `tearDownClass` (Per Test Class)
Use `setUpClass` to prepare resources *once for all test methods in the class* and `tearDownClass` to clean up *once after all test methods*. This is suitable for expensive, shared resources.

```python
import unittest
from unittest.mock import MagicMock

class TestExpensiveResource(unittest.TestCase):
    expensive_resource: MagicMock

    @classmethod
    def setUpClass(cls) -> None:
        cls.expensive_resource = MagicMock() # e.g., a test server
        cls.expensive_resource.start()

    @classmethod
    def tearDownClass(cls) -> None:
        cls.expensive_resource.stop()

    def test_resource_is_available(self) -> None:
        self.expensive_resource.is_running.return_value = True
        self.assertTrue(self.expensive_resource.is_running())
```

## 4. Mocking Strategies (`unittest.mock`)

Isolate the unit under test by replacing external dependencies with `MagicMock` objects.

### Use `patch` Decorator
For simple patching, the `@patch` decorator is concise.

```python
from unittest.mock import patch
import unittest

# Assume 'my_module' has a function 'get_external_data'
# and 'my_service' uses 'my_module.get_external_data'
class MyService:
    def process_data(self) -> str:
        data = my_module.get_external_data()
        return f"processed_{data['key']}"

class TestMyService(unittest.TestCase):
    @patch('my_module.get_external_data')
    def test_service_processes_data_correctly(self, mock_get_data: MagicMock) -> None:
        mock_get_data.return_value = {"key": "mocked_value"}
        service = MyService()
        result = service.process_data()
        self.assertEqual(result, "processed_mocked_value")
        mock_get_data.assert_called_once()
```

### Use `patch` as a Context Manager
For patching within a specific block of code, use `with patch(...)`.

```python
from unittest.mock import patch, MagicMock
import unittest

class TestMyService(unittest.TestCase):
    def test_service_handles_no_data(self) -> None:
        with patch('my_module.get_external_data') as mock_get_data:
            mock_get_data.return_value = None
            service = MyService()
            result = service.process_data()
            self.assertIsNone(result)
```

### Avoid Over-Mocking
Only mock external boundaries or complex dependencies. Do not mock internal logic or objects that are part of the unit under test.

❌ BAD:
```python
# Testing a 'User' class where 'is_admin' is a simple property
class TestUser(unittest.TestCase):
    @patch.object(User, 'is_admin') # Mocking an internal property
    def test_admin_user_can_access_panel(self, mock_is_admin: MagicMock) -> None:
        user = User(role='admin')
        mock_is_admin.return_value = True
        self.assertTrue(user.can_access_admin_panel())
```

✅ GOOD:
```python
# Testing a 'User' class where 'is_admin' is a simple property
class TestUser(unittest.TestCase):
    def test_admin_user_can_access_panel(self) -> None:
        user = User(role='admin') # Direct instantiation
        self.assertTrue(user.can_access_admin_panel())
```

## 5. Performance Considerations

Fast tests encourage frequent execution.

### Isolate Tests
Ensure tests are independent and don't rely on the order of execution or shared mutable state. Use `setUp`/`tearDown` to reset state.

### Mock Slow I/O
Replace database calls, network requests, and file system operations with mocks to avoid performance bottlenecks.

### Separate Integration Tests
If a test *must* interact with a real external system (e.g., a database), mark it as an integration test and run it separately from fast unit tests. `unittest` doesn't have built-in marking like `pytest`, so use naming conventions (e.g., `test_integration_*.py` files).

## 6. Type Hints in Tests

Apply type hints to test methods, fixture methods, and local variables for improved readability, maintainability, and static analysis.

```python
import unittest
from typing import Any
from unittest.mock import MagicMock

class TestDatabaseOperations(unittest.TestCase):
    db_connection: MagicMock # Type hint for instance variable

    def setUp(self) -> None:
        self.db_connection = MagicMock()
        self.db_connection.create_table("users")

    def tearDown(self) -> None:
        self.db_connection.drop_table("users")
        self.db_connection.close()

    def test_add_user_to_db(self) -> None:
        user_name: str = "Alice" # Type hint for local variable
        self.db_connection.insert("users", {"name": user_name})
        self.db_connection.insert.assert_called_once_with("users", {"name": user_name})
```

## 7. Coverage Patterns

While `unittest` doesn't provide coverage tools, integrate `coverage.py` to ensure thorough testing.

### Enforce Coverage Thresholds
Configure `coverage.py` in `pyproject.toml` or `setup.cfg` to fail CI builds if coverage drops below a set percentage.

```toml
# pyproject.toml (example for coverage.py)
[tool.coverage.run]
source = ["my_app"] # Specify which code to measure

[tool.coverage.report]
fail_under = 90 # Fail if total coverage is below 90%
show_missing = true
```

### Focus on Branches and Statements
Prioritize covering critical paths, edge cases, and error handling over simply reaching 100% line coverage.

© sanjeed5 · CC0-1.0 · sanjeed5/awesome-cursor-rules-mdc

Смотрите также

Спонсоры проекта

Компании, которые помогают держать аналитику открытой