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

nose2 — правило для Cursor: что делает и как установить

Инструкция для Cursor по оформлению тестов на nose2 с конфигурацией в pyproject.toml и настройкой сбора coverage.

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

Что делает nose2

Правило задаёт стандарты тестирования Python-проектов через фреймворк nose2. Ассистент ориентируется на выделенный каталог tests/, маску имён файлов test_*.py и запрещает сырые инструкции assert в пользу методов self.assert* из unittest.TestCase.

Все параметры тестов фиксируются в файле pyproject.toml внутри секции [tool.nose2], без устаревших файлов unittest.cfg. Для параметризации тестов подключается плагин nose2.plugins.params с декоратором @params, а внешние сервисы изолируются через unittest.mock.patch.

Без отдельной установки пакета coverage через pip плагин покрытия в nose2 работать не сможет. Настройки покрытия требуют явного указания coverage-combine = true, иначе отчёты ломаются при использовании multiprocessing в CI.

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

  • сконфигурировать nose2 и плагины в pyproject.toml
  • параметризовать тесты с помощью nose2.tools.params
  • заменить сырые assert на методы unittest.TestCase
  • настроить сбор отчётов coverage в многопроцессном режиме

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

  • Напиши параметризованный тест для проверки расчёта скидки через nose2.tools.params.
  • Сконфигурируй секцию [tool.nose2] в pyproject.toml с плагинами coverage и junitxml.
  • Перепиши test_api.py с наследованием от unittest.TestCase и методами assertEqual.

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

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

.cursor/rules/nose2.mdc

Во frontmatter: description, globs, alwaysApply

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

Вопросы о nose2

Как установить nose2 в Cursor?

Сохраните файл правила по пути .cursor/rules/nose2.mdc в корне проекта.

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

Задаёт структуру каталога tests/, настройки pyproject.toml и отказ от сырых проверок assert.

Куда выносить конфигурацию nose2?

Все настройки размещаются в pyproject.toml под секцией [tool.nose2], исключая файлы unittest.cfg и nose2.cfg.

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

nose2.mdc · CC0-1.0
---
description: This rule file provides opinionated best practices for writing, organizing, and configuring tests using nose2, emphasizing modern Python development workflows and common pitfalls.
globs: **/*.py
---
# nose2 Best Practices

`nose2` is the modern successor to `nose`, built upon Python's `unittest` module. It offers powerful test discovery, a plugin architecture, and helpers for writing clean, maintainable test suites. This guide outlines essential best practices for leveraging `nose2` effectively in your projects.

## 1. Project Layout & Naming

Always organize your tests in a dedicated `tests/` directory at the root of your project. Name test files consistently using the `test_*.py` pattern. This ensures `nose2`'s default discovery works reliably.

**❌ BAD: Scattered tests or inconsistent naming**
```
# Project root
my_module/
  feature_a.py
  feature_a_tests.py  # Inconsistent naming
  test_feature_b.py   # Mixed with source
```

**✅ GOOD: Dedicated `tests/` directory and `test_*.py` naming**
```
# Project root
my_module/
  __init__.py
  feature_a.py
  feature_b.py
tests/
  __init__.py
  test_feature_a.py
  test_feature_b.py
```

## 2. Configuration (`pyproject.toml`)

Centralize all `nose2` configuration within your `pyproject.toml` file under the `[tool.nose2]` table. This keeps your project configuration tidy, version-controlled, and compatible with modern Python tooling. Avoid `unittest.cfg` or `nose2.cfg` for new projects.

**❌ BAD: Using legacy `.cfg` files**
```ini
# unittest.cfg
[unittest]
start-dir = tests
```

**✅ GOOD: `pyproject.toml` for all configuration**
```toml
# pyproject.toml
[tool.nose2]
start-dir = "tests"
code-directories = ["src"] # Add your source code directories to sys.path if needed
plugins = [
    "nose2.plugins.coverage",
    "nose2.plugins.params",
    "nose2.plugins.junitxml",
]
exclude-plugins = [
    "nose2.plugins.loader.functions", # Avoid loading plain functions as tests
]

[tool.nose2.coverage]
always-on = true
coverage-combine = true # Essential for multiprocessing
coverage-report = ["term", "html"]
coverage-config = ".coveragerc"
```

## 3. Test Structure & Assertions

All tests must inherit from `unittest.TestCase`. Inside your test methods, use `self.assert*` methods provided by `unittest.TestCase` for detailed failure reports. Avoid raw `assert` statements, as they offer less diagnostic information on failure.

**❌ BAD: Raw `assert` statements**
```python
import unittest

class MyFeatureTest(unittest.TestCase):
    def test_addition(self):
        result = 1 + 1
        assert result == 3, "Addition failed" # Vague error message
```

**✅ GOOD: `unittest.TestCase` and `self.assert*` methods**
```python
import unittest

class MyFeatureTest(unittest.TestCase):
    def test_addition(self0):
        result = 1 + 1
        self.assertEqual(result, 2, "Addition should be 2") # Specific error message
        self.assertNotEqual(result, 3)
```

## 4. Setup/Teardown

Utilize `setUp` and `tearDown` methods within your `unittest.TestCase` classes for per-test setup and cleanup. For class-level setup/teardown, use `setUpClass` and `tearDownClass`. Avoid module-level `setup()`/`teardown()` functions unless maintaining legacy `nose` suites.

**❌ BAD: Module-level setup/teardown (legacy `nose` style)**
```python
# test_db_operations.py
DB_CONNECTION = None

def setup_module():
    global DB_CONNECTION
    DB_CONNECTION = connect_to_db()

def teardown_module():
    DB_CONNECTION.close()

class DatabaseTest(unittest.TestCase):
    def test_query(self):
        # ... use DB_CONNECTION ...
        pass
```

**✅ GOOD: Class-level `setUp`/`tearDown` for fixtures**
```python
import unittest
from my_module.db import connect_to_db, disconnect_from_db

class DatabaseTest(unittest.TestCase):
    @classmethod
    def setUpClass(cls) -> None:
        """Connect to the database once for all tests in this class."""
        cls.db_connection = connect_to_db()

    @classmethod
    def tearDownClass(cls) -> None:
        """Disconnect from the database after all tests in this class."""
        disconnect_from_db(cls.db_connection)

    def setUp(self) -> None:
        """Reset database state before each test."""
        self.db_connection.clear_data()

    def test_insert_user(self) -> None:
        self.db_connection.insert("users", {"name": "Alice"})
        user = self.db_connection.get("users", "Alice")
        self.assertIsNotNone(user)

    def test_delete_user(self) -> None:
        self.db_connection.insert("users", {"name": "Bob"})
        self.db_connection.delete("users", "Bob")
        user = self.db_connection.get("users", "Bob")
        self.assertIsNone(user)
```

## 5. Parameterized Tests

Leverage `nose2.tools.params` for writing data-driven tests. This significantly reduces boilerplate when you need to run the same test logic with different input data. Ensure the `nose2.plugins.params` plugin is enabled in `pyproject.toml`.

**❌ BAD: Duplicating test logic for different inputs**
```python
import unittest

class CalculatorTest(unittest.TestCase):
    def test_add_positive(self):
        self.assertEqual(add(1, 2), 3)
    def test_add_negative(self):
        self.assertEqual(add(-1, -2), -3)
    def test_add_zero(self):
        self.assertEqual(add(0, 5), 5)
```

**✅ GOOD: Using `nose2.tools.params`**
```python
import unittest
from nose2.tools import params

class CalculatorTest(unittest.TestCase):
    @params(
        (1, 2, 3),
        (-1, -2, -3),
        (0, 5, 5),
        (10, -3, 7)
    )
    def test_add(self, a: int, b: int, expected: int) -> None:
        self.assertEqual(add(a, b), expected)
```

## 6. Coverage & CI Integration

Enable the `coverage` plugin and set `coverage-combine = true` in `pyproject.toml` to ensure accurate coverage reporting, especially in environments using multiprocessing. Run `nose2 -v` in your CI pipeline and enforce a coverage threshold to prevent regressions.

**Actionable Steps:**
1. Install `coverage`: `pip install coverage`
2. Configure `pyproject.toml` (as shown in section 2).
3. Run tests with coverage in CI: `nose2 -v`
4. Use `coverage report` or `coverage html` to view results.
5. Enforce a minimum coverage percentage in your CI/CD pipeline.

## 7. Mocking Strategies

Use Python's built-in `unittest.mock` library for isolating units under test from their dependencies. Prefer `mock.patch` as a decorator or context manager for clear and scoped mocking.

**❌ BAD: Manually replacing dependencies or global state**
```python
# my_module.py
import external_service

def process_data(data):
    return external_service.send(data)

# test_my_module.py
import unittest
import my_module
import external_service # This will be the real service

class MyModuleTest(unittest.TestCase):
    def test_process_data(self):
        # This is bad, it affects the actual external_service module
        original_send = external_service.send
        external_service.send = lambda x: "mocked_response"
        result = my_module.process_data("test_data")
        self.assertEqual(result, "mocked_response")
        external_service.send = original_send # Must remember to clean up
```

**✅ GOOD: Using `unittest.mock.patch`**
```python
import unittest
from unittest import mock
from my_module import process_data # Assuming process_data is in my_module.py

class MyModuleTest(unittest.TestCase):
    @mock.patch('my_module.external_service.send') # Patch the dependency where it's looked up
    def test_process_data_decorator(self, mock_send):
        mock_send.return_value = "mocked_response_from_decorator"
        result = process_data("test_data")
        mock_send.assert_called_once_with("test_data")
        self.assertEqual(result, "mocked_response_from_decorator")

    def test_process_data_context_manager(self):
        with mock.patch('my_module.external_service.send') as mock_send:
            mock_send.return_value = "mocked_response_from_context"
            result = process_data("another_data")
            mock_send.assert_called_once_with("another_data")
            self.assertEqual(result, "mocked_response_from_context")
```

## 8. Type Hints

Apply type hints consistently to your test code, especially for method signatures (`setUp`, `test_*`, `tearDown`). This improves readability, enables static analysis, and makes your tests easier to understand and maintain.

**❌ BAD: Untyped test methods**
```python
class MyTest(unittest.TestCase):
    def setUp(self):
        self.client = create_test_client()

    def test_endpoint(self):
        response = self.client.get('/api/data')
        self.assertEqual(response.status_code, 200)
```

**✅ GOOD: Type-hinted test methods**
```python
from typing import Any
import unittest

class MyTest(unittest.TestCase):
    client: Any # Define attributes used across methods

    def setUp(self) -> None:
        self.client = create_test_client()

    def test_endpoint(self) -> None:
        response = self.client.get('/api/data')
        self.assertEqual(response.status_code, 200)
```

## 9. Common Pitfalls & Gotchas

*   **Not staying current:** `nose2` is actively maintained. Always use the latest stable release (0.15.x as of May 2024) to benefit from bug fixes, new features, and Python version compatibility.
*   **Overly complex `setUp`:** Keep `setUp` methods focused on preparing the immediate test context. If setup becomes too complex, consider breaking tests into smaller, more focused classes or using factories.
*   **Mixing `nose` and `nose2` idioms:** `nose2` is a distinct project. Avoid relying on `nose`-specific features that `nose2` explicitly does not support (e.g., certain module-level functions or specific test discovery quirks).
*   **When to consider `pytest`:** If `nose2`'s `unittest`-centric approach feels restrictive, or you find yourself fighting its conventions, consider migrating to `pytest`. `pytest` offers a more "Pythonic" test syntax (raw `assert`), powerful fixtures, and a vast plugin ecosystem. `pytest` can run `nose`-style tests, making migration easier.

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

Похожие правила IDE

Все правила IDE по теме «Тесты и QA» →
python-pypi-package-builder официальный github Скилл помогает собрать Python-пакет, проверить его, настроить версию и опубликовать в PyPI. Подойдёт для библиотек, SDK, CLI и плагинов. 943установок python-testing-patterns Seth Hobson Скилл помогает писать тесты Python с pytest, фикстурами и моками. Подходит для настройки тестового набора и отладки падающих проверок. CX Codex 36 943установок python-design-patterns Seth Hobson Помогает выбирать структуру Python-кода, разделять обязанности и решать, когда выносить повторяющуюся логику в абстракцию. Пригодится при проектировании и рефакторинге. CX Codex 22 842установок python-testing affaan-m Скилл задаёт подход к тестам Python на pytest: TDD, фикстуры, моки, параметризацию и проверку покрытия. Пригодится при создании и ревью тестов. CX Codex +1 4 900установок django-verification affaan-m Прогоняет 12 фаз проверки Django-проекта: окружение, линтеры, миграции, тесты с покрытием, безопасность и diff. Пригодится перед PR и деплоем. CX Codex +1 4 600установок golang-stretchr-testify samber Направляет агента при написании тестов на Go с библиотекой stretchr/testify. Помогает разделять assert и require, строить моки и запускать тестовые сьюты. CX Codex +1 39 400установок

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

Весь набор →
nuxt Правило для Cursor задаёт агенту стиль кода в Nuxt-проекте: структура каталогов, Composition API, Pinia, useFetch. Пригодится, если агент уже начал плодить миксины и onMounted вместо SSR-фетча. ★ 3 580звёзд репо numpy Правило заставляет Cursor генерировать векторизованный код NumPy без медленных циклов Python. Помогает писать быстрые модульные функции с явным указанием dtype. ★ 3 580звёзд репо numba Правило задаёт практики для Numba-кода на Python: CPU-ускорение, CUDA-ядра и работу с массивами. Пригодится для численных задач в .py. ★ 3 580звёзд репо notion-api Правило для Cursor задаёт, как писать код интеграций с Notion API: модули, токены в переменных окружения, официальные SDK и пагинация. ★ 3 580звёзд репо nltk Правило задаёт практики для NLTK-кода на Python: модульная структура, типизация, загрузка данных и выбор токенизатора. ★ 3 580звёзд репо nginx Правило для Cursor задаёт, как писать конфиги NGINX: модульные include-файлы, современный TLS, кэш и лимиты. Пригодится, если агент правит nginx.conf в вашем проекте. ★ 3 580звёзд репо next-js Задаёт стандарты разработки на Next.js в Cursor: изолирует фичи в папке app, держит компоненты серверными и запрещает теги img. ★ 3 580звёзд репо netlify Правило задаёт практики для сборки и поддержки проектов на Netlify: настройки деплоя, работа с секретами, проверки и доступность. Помогает сверить конфигурацию перед публикацией. ★ 3 580звёзд репо

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

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