pytest-drill-sergeant


Namepytest-drill-sergeant JSON
Version 0.1.0 PyPI version JSON
download
home_pageNone
SummaryA pytest plugin that enforces test quality standards through automatic marker detection and AAA structure validation
upload_time2025-09-02 20:37:21
maintainerNone
docs_urlNone
authorNone
requires_python>=3.12
licenseMIT
keywords pytest testing quality standards aaa markers
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # ๐ŸŽ–๏ธ Pytest Drill Sergeant

<!-- CI/CD Battle Status -->
[![CI Status](https://github.com/jeffrichley/pytest-drill-sergeant/workflows/CI%20(nox)/badge.svg)](https://github.com/jeffrichley/pytest-drill-sergeant/actions)
[![codecov](https://codecov.io/gh/jeffrichley/pytest-drill-sergeant/branch/main/graph/badge.svg)](https://codecov.io/gh/jeffrichley/pytest-drill-sergeant)
[![Quality Gate](https://img.shields.io/badge/quality-A%2B-brightgreen?style=flat&logo=codacy)](https://github.com/jeffrichley/pytest-drill-sergeant)

<!-- Package Battle Metrics -->
[![PyPI version](https://badge.fury.io/py/pytest-drill-sergeant.svg)](https://badge.fury.io/py/pytest-drill-sergeant)
[![Python versions](https://img.shields.io/pypi/pyversions/pytest-drill-sergeant.svg)](https://pypi.org/project/pytest-drill-sergeant/)
[![Downloads](https://pepy.tech/badge/pytest-drill-sergeant)](https://pepy.tech/project/pytest-drill-sergeant)

<!-- Platform Combat Readiness -->
[![Platforms](https://img.shields.io/badge/platforms-Linux%20%7C%20macOS%20%7C%20Windows-blue)](https://github.com/jeffrichley/pytest-drill-sergeant/actions)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)

<!-- Military Honors & Achievements -->
[![Tested](https://img.shields.io/badge/battle--tested-6%20environments-red?style=flat&logo=pytest)](https://github.com/jeffrichley/pytest-drill-sergeant/actions)
[![Type Checked](https://img.shields.io/badge/type--checked-mypy-blue?style=flat&logo=python)](https://github.com/jeffrichley/pytest-drill-sergeant)
[![Drill Sergeant Approved](https://img.shields.io/badge/drill%20sergeant-approved%20%F0%9F%8E%96%EF%B8%8F-brightgreen)](https://github.com/jeffrichley/pytest-drill-sergeant)

**LISTEN UP, MAGGOTS! ๐Ÿ—ฃ๏ธ**

Your test suite is a DISASTER! Tests scattered everywhere like a tornado hit your codebase, no markers, no structure, and don't even get me started on your "AAA" pattern that looks more like "Aaahhh-what-am-I-even-testing" pattern.

**The Drill Sergeant is here to whip your tests into shape!** ๐Ÿ’ช

This pytest plugin will turn your chaotic test mess into a disciplined, well-organized military formation. No mercy. No exceptions. Only QUALITY.

## ๐Ÿ… Live Battle Intelligence (Auto-Updating Intel)

| **Metric** | **Live Status** | **Military Assessment** |
|------------|-----------------|-------------------------|
| **๐Ÿ“ฆ Codebase Size** | [![Files](https://img.shields.io/github/directory-file-count/jeffrichley/pytest-drill-sergeant/src?label=source%20files&logo=python&color=blue)](https://github.com/jeffrichley/pytest-drill-sergeant) | *"Lean and mean - no bloat allowed!"* |
| **โญ Bug Reports** | [![GitHub issues](https://img.shields.io/github/issues/jeffrichley/pytest-drill-sergeant?label=open%20issues&logo=github)](https://github.com/jeffrichley/pytest-drill-sergeant/issues) | *"Zero tolerance for battlefield failures!"* |
| **๐Ÿ“ˆ Activity Level** | [![Commits](https://img.shields.io/github/commit-activity/m/jeffrichley/pytest-drill-sergeant?label=monthly%20commits&logo=git&color=green)](https://github.com/jeffrichley/pytest-drill-sergeant) | *"Active military operations in progress!"* |
| **โšก Response Time** | [![GitHub last commit](https://img.shields.io/github/last-commit/jeffrichley/pytest-drill-sergeant?label=last%20deployment&logo=github-actions)](https://github.com/jeffrichley/pytest-drill-sergeant) | *"Always ready for action!"* |
| **๐ŸŽฏ Stars Earned** | [![GitHub stars](https://img.shields.io/github/stars/jeffrichley/pytest-drill-sergeant?label=stars&logo=github&color=yellow)](https://github.com/jeffrichley/pytest-drill-sergeant) | *"Recognition from fellow soldiers!"* |

**The Drill Sergeant's Live Record:** *"All systems operational, zero compromises accepted!"* ๐ŸŽ–๏ธ

## ๐ŸŽฏ What This Bad Boy Does

- **๐Ÿท๏ธ Automatic Marker Detection** - Because apparently you can't be trusted to add `@pytest.mark.unit` yourself
- **๐Ÿ“ AAA Structure Enforcement** - "Arrange-Act-Assert" not "Arrange-Act-And-Hope-It-Works"  
- **๐Ÿ’ฅ Comprehensive Error Messages** - So detailed even your manager could understand what you did wrong
- **๐Ÿšจ Zero Tolerance Policy** - One violation = one failed test. NO EXCEPTIONS!

## ๐Ÿš€ Installation (AKA Basic Training)

### For Smart Developers

```bash
# Development dependency (where it belongs, recruit!)
uv add --group dev pytest-drill-sergeant

# Or if you're still using that ancient pip thing...
pip install pytest-drill-sergeant
```

### For "Special" Developers

```bash
# Runtime dependency (really? You need test quality enforcement in production?)
uv add pytest-drill-sergeant
```

## ๐ŸŽ–๏ธ Advanced Arsenal (Secret Weapons Unlocked)

[![AAA Structure](https://img.shields.io/badge/AAA-Arrange%20Act%20Assert-blue?style=for-the-badge&logo=checkmarx)](https://github.com/jeffrichley/pytest-drill-sergeant)
[![Auto Detection](https://img.shields.io/badge/Auto--Detection-16%20Built--in%20Mappings-green?style=for-the-badge&logo=target)](https://github.com/jeffrichley/pytest-drill-sergeant)
[![Synonyms](https://img.shields.io/badge/Synonyms-Given%2FWhen%2FThen%20Support-purple?style=for-the-badge&logo=language)](https://github.com/jeffrichley/pytest-drill-sergeant)
[![Zero Config](https://img.shields.io/badge/Zero--Config-Ready%20to%20Deploy-orange?style=for-the-badge&logo=rocket)](https://github.com/jeffrichley/pytest-drill-sergeant)

## ๐Ÿ“ Before vs After (Prepare to be AMAZED)

### Before: Your Disaster Zone ๐Ÿ”ฅ

```python
# tests/whatever/test_something.py (what kind of name is that?!)
def test_thing():
    x = Calculator()
    result = x.add(1, 2)
    assert result == 3  # Wow, such insight. Much test. Very quality.
```

**Drill Sergeant says:** *WHAT IS THIS GARBAGE? No marker, no structure, and it's in a random directory! This test FAILS until you fix it!*

### After: PROPER MILITARY FORMATION ๐ŸŽ–๏ธ

```python
# tests/unit/test_calculator.py (NOW we're talking!)
import pytest

@pytest.mark.unit  # AUTOMATIC! The Sergeant detects from directory and adds this! ๐ŸŽฏ
def test_addition_with_positive_numbers():
    """Test addition functionality with positive integers."""
    # Arrange - Set up your battlefield, soldier!
    calculator = Calculator()
    first_operand = 5
    second_operand = 3
    expected_sum = 8
    
    # Act - Execute the mission!
    actual_sum = calculator.add(first_operand, second_operand)
    
    # Assert - Verify victory conditions!
    assert actual_sum == expected_sum
```

**Drill Sergeant says:** *OUTSTANDING! This is what DISCIPLINE looks like!*

### For Simple Tests (One-Liner AAA)

Sometimes your test is so simple that combining AAA sections makes sense:

```python
@pytest.mark.unit
def test_simple_calculation():
    """Test basic arithmetic operation."""
    # Arrange and Act - Set up calculator and perform addition
    result = Calculator().add(2, 3)
    
    # Assert - Verify the calculation is correct
    assert result == 5

@pytest.mark.unit  
def test_ultra_simple():
    """Test with all AAA in one comment (for the truly lazy)."""
    # Arrange, Act, and Assert - Create, call, and verify in one swift motion
    assert Calculator().multiply(4, 2) == 8
```

**Drill Sergeant says:** *Fine, soldier. Sometimes efficiency trumps ceremony. But don't get TOO comfortable!*

## ๐ŸŽ–๏ธ Automatic Marker Detection (Because You're Lazy)

The Drill Sergeant isn't just here to yell at you - he's here to HELP. Place your tests in the right directories and watch the magic happen:

| Directory | Auto-Applied Marker | What It Means |
|-----------|-------------------|---------------|
| `tests/unit/` | `@pytest.mark.unit` | Fast, isolated tests |
| `tests/integration/` | `@pytest.mark.integration` | Tests multiple components |
| `tests/e2e/` | `@pytest.mark.e2e` | End-to-end user scenarios |
| `tests/api/` | `@pytest.mark.integration` | API endpoint tests |
| `tests/performance/` | `@pytest.mark.performance` | Speed/load tests |
| `tests/smoke/` | `@pytest.mark.integration` | Quick sanity checks |

**16 built-in mappings** so you don't have to think too hard! ๐Ÿง   
*(I've seen you think, and it ain't pretty!)*

### How It Works

1. **You write a test** (hopefully)
2. **Forget to add a marker** (as usual)  
3. **Drill Sergeant detects directory** (`tests/unit/test_foo.py`)
4. **AUTOMATICALLY MODIFIES your test function** to add `@pytest.mark.unit`
5. **Test passes as if you had added the marker yourself** ๐ŸŽญ
6. **You look competent** (even though the Sergeant did the work)

## ๐Ÿ”ง Configuration (For Control Freaks)

### The Nuclear Option: Turn Everything Off

```ini
# pytest.ini
[tool:pytest]
drill_sergeant_enabled = false
```

**Drill Sergeant says:** *You're on your own, soldier. Don't come crying when your tests are garbage.*

### Selective Enforcement (Baby Steps)  
*When you can't handle the full military experience and need training wheels* ๐Ÿšฒ

```ini
# pytest.ini
[tool:pytest]
drill_sergeant_enforce_markers = true      # YES! ENFORCE THE MARKERS!
drill_sergeant_enforce_aaa = false         # Fine, be sloppy with your structure
drill_sergeant_auto_detect_markers = true  # Let me do your job for you
drill_sergeant_min_description_length = 5  # At least TRY to be descriptive
```

### Custom Mappings (For Special Snowflakes)

```ini
# pytest.ini
[tool:pytest]
# Format: directory_name=marker_name (maps test directories to pytest markers)
drill_sergeant_marker_mappings = contract=api,smoke=integration,load=performance
# Translation for civilians: 
# tests/contract/ โ†’ @pytest.mark.api
# tests/smoke/ โ†’ @pytest.mark.integration
# tests/load/ โ†’ @pytest.mark.performance
```

Or via environment (because you love complexity):

```bash
# Same format: directory=marker pairs
export DRILL_SERGEANT_MARKER_MAPPINGS="widget=unit,gizmo=integration"
# For those who need it spelled out: 
# tests/widget/ โ†’ @pytest.mark.unit
# tests/gizmo/ โ†’ @pytest.mark.integration
```

## ๐ŸŽญ Error Messages That Don't Suck

When you inevitably mess up, the Drill Sergeant doesn't just say "test failed" like some amateur plugin. Oh no. You get the FULL TREATMENT:

```
โŒ CODE QUALITY: Test 'test_disaster' violates project standards by missing test annotations and missing AAA structure
๐Ÿ“‹ 3 requirement(s) must be fixed before this test can run:

๐Ÿท๏ธ  MISSING TEST CLASSIFICATION:
   โ€ข Add @pytest.mark.unit, @pytest.mark.integration, or move test to appropriate directory structure

๐Ÿ“ MISSING AAA STRUCTURE (Arrange-Act-Assert):
   โ€ข Add '# Arrange - description of what is being set up' comment before test setup
   โ€ข Add '# Act - description of what action is being performed' comment before test action

โ„น๏ธ  This is a PROJECT REQUIREMENT for all tests to ensure:
   โ€ข Consistent test structure and readability
   โ€ข Proper test categorization for CI/CD pipelines
   โ€ข Maintainable test suite following industry standards

๐Ÿ“š For examples and detailed requirements:
   โ€ข https://github.com/jeffrichley/pytest-drill-sergeant
   โ€ข pytest.ini (for valid markers)
```

**Translation:** *Your test is bad and you should feel bad. Here's exactly how to fix it.*

## ๐ŸŽช Configuration Examples (Real World Scenarios)

### The "I'm New Here" Setup

```ini
# pytest.ini - Training wheels ON
[tool:pytest]
drill_sergeant_enabled = true
drill_sergeant_enforce_markers = false     # Baby steps
drill_sergeant_enforce_aaa = true          # Learn structure first
drill_sergeant_auto_detect_markers = true  # Let the magic happen
```

### The "CI/CD Enforcer" Setup

```ini
# pytest.ini - NO MERCY in production
[tool:pytest]
drill_sergeant_enabled = true
drill_sergeant_enforce_markers = true      # ZERO TOLERANCE
drill_sergeant_enforce_aaa = true          # PERFECT STRUCTURE
drill_sergeant_auto_detect_markers = false # Do it yourself, lazy!
```

### The "Legacy Codebase Survival" Setup

```ini
# pytest.ini - Gradual improvement without mass suicide
[tool:pytest]
drill_sergeant_enabled = true
drill_sergeant_enforce_markers = false     # Skip marker enforcement for now
drill_sergeant_enforce_aaa = true          # Fix structure first
drill_sergeant_auto_detect_markers = true  # Auto-add markers where possible
```

## ๐ŸŽจ Environment Variables (For the DevOps Heroes)

Control the Drill Sergeant from your environment like a puppet master:

```bash
# Turn the drill sergeant into a teddy bear
export DRILL_SERGEANT_ENABLED=false

# Make him extra mean about markers
export DRILL_SERGEANT_ENFORCE_MARKERS=true

# Demand War and Peace level descriptions
export DRILL_SERGEANT_MIN_DESCRIPTION_LENGTH=50

# Custom directory mappings for your special setup
export DRILL_SERGEANT_MARKER_MAPPINGS="widgets=unit,chaos=stress"
```

## ๐ŸŽญ AAA Synonym Recognition (Because Apparently You're All Special Snowflakes! โ„๏ธ)

### The Problem: "You're Too Good for Military Vocabulary" ๐Ÿ˜ค

Oh, so the Drill Sergeant's perfectly good vocabulary isn't fancy enough for you? You can't be bothered to learn basic military terminology that's been battle-tested across thousands of codebases? 

**Let me guess:**
- "Arrange" is too *corporate* for your hip startup? ๐Ÿ™„
- "Act" doesn't capture your *artistic vision* of test methodology? ๐ŸŽจ
- "Assert" sounds too *aggressive* for your safe space codebase? ๐Ÿณ๏ธ

**Fine. FINE!** The Drill Sergeant will swallow his pride and learn your precious little words. But don't think for a second that lowering his standards to accommodate your delicate sensibilities makes him happy about it.

### The Solution: Synonym Recognition (AKA "Participation Trophy Mode") ๐Ÿ†

*Against his better judgment*, the Sergeant can be taught new vocabulary. He'll grumble about it, but he'll do it. Because apparently "professional military standards" aren't good enough for you people.

#### Enable This Madness:

```ini
# pytest.ini - Enabling the coddling of your fragile vocabulary preferences
[tool:pytest]
drill_sergeant_aaa_synonyms_enabled = true  # *Heavy military sighing* ๐Ÿ˜ฎโ€๐Ÿ’จ
```

#### Built-in Synonyms (Because I Apparently Have to Do Everything for You):

**Arrange Synonyms:** Setup, Given, Prepare, Initialize, Configure, Create, Build  
*"Setup? SETUP?! It's called ARRANGE! But sure, let's use baby words..."*

**Act Synonyms:** Call, Execute, Run, Invoke, Perform, Trigger, When  
*"I suppose 'When' is more gentle than 'Act'. Wouldn't want to trigger anyone..."*

**Assert Synonyms:** Verify, Check, Expect, Validate, Confirm, Ensure, Then  
*"Oh, we can't 'Assert' things anymore? Too confrontational? My mistake, let's 'gently verify'..."*

#### Now These ALL Work! (God Help Us All) ๐ŸŽ‰

```python
def test_user_authentication():
    # Setup user credentials and mock database
    user = User(username="test_user")
    
    # Call the authentication service 
    result = auth_service.authenticate(user.username, "password123")
    
    # Verify successful authentication
    assert result.success is True
```

**Drill Sergeant internal monologue:** *"'Setup'... 'Call'... 'Verify'... What's next, 'Pretty please test my code'? In my day, we had STANDARDS! But nooooo, everyone's a special butterfly with their own vocabulary..."* ๐Ÿฆ‹

```python  
def test_bdd_style():
    # Given a valid shopping cart with items
    cart = ShoppingCart()
    cart.add_item("widget", price=10.00)
    
    # When calculating the total price
    total = cart.calculate_total()
    
    # Then the result should include tax
    assert total == 10.80  # 8% tax included
```

**Drill Sergeant:** *"Oh look, BDD! 'Given/When/Then' - how PRECIOUS! Let me guess, you also use 'user stories' instead of requirements and call bugs 'opportunities for improvement'? Next you'll want me to validate your feelings instead of your code!"* ๐Ÿ’…

#### Custom Synonyms (For Extra Special Snowflakes):

Oh, the built-in synonyms aren't unique enough for you? You need your OWN PERSONAL vocabulary? Of course you do. ๐Ÿ™„

```ini
# pytest.ini - Because you're just THAT special
drill_sergeant_aaa_arrange_synonyms = Background,Precondition,Setup
drill_sergeant_aaa_act_synonyms = Execute,Trigger,Action  
drill_sergeant_aaa_assert_synonyms = Expect,Outcome,Result
```

*"Let me guess - your team is 'different' and 'innovative' and needs custom words to express your unique testing philosophy? Can't just use the same words as literally everyone else in the industry?"*

```python
def test_with_custom_vocabulary():
    # Background - Configure the test environment  
    api_client = APIClient(base_url="https://test.api.com")
    
    # Execute - Trigger the user creation endpoint
    response = api_client.create_user({"name": "John", "email": "john@test.com"})
    
    # Expect - Result should be successful user creation
    assert response.status_code == 201
    assert response.json()["user"]["name"] == "John"
```

**Drill Sergeant:** *"'Background'? 'Execute'? 'Expect'? What are you, writing poetry? It's a TEST, not a haiku! But fine, I'll learn your artisanal vocabulary. Just don't expect me to like it."* ๐Ÿ“

#### Environment Variable Control (For the Control Freaks):

Because apparently config files are too mainstream for you? You need ENVIRONMENT VARIABLES? ๐ŸŒ

```bash
# Enable this circus of accommodation
export DRILL_SERGEANT_AAA_SYNONYMS_ENABLED=true

# Reject all my hard work and use only your precious custom words
export DRILL_SERGEANT_AAA_BUILTIN_SYNONYMS=false

# Define your team's "unique" vocabulary (eye roll intensifies)
export DRILL_SERGEANT_AAA_ARRANGE_SYNONYMS="Setup,Given,Background"
export DRILL_SERGEANT_AAA_ACT_SYNONYMS="When,Call,Execute"
export DRILL_SERGEANT_AAA_ASSERT_SYNONYMS="Then,Verify,Check"
```

*"Oh sure, let's make it even MORE complicated! Why have one place to configure things when you can have seventeen different ways? This is why we can't have nice things."* ๐Ÿคฆโ€โ™‚๏ธ

#### Backward Compatibility (Because I'm Not a Complete Monster): โœ…

Look, I may be bitter about this whole "synonym accommodation" situation, but I'm not going to break your existing code. I have SOME integrity left.

- **Default: DISABLED** - Because I refuse to enable this madness by default
- **Original keywords always work** - "Arrange/Act/Assert" will NEVER be deprecated (unlike my dignity)
- **Explicit opt-in** - You have to ASK for this nonsense explicitly
- **Layered configuration** - Environment variables override pytest.ini because apparently you need 47 ways to configure everything

**The Drill Sergeant's Reluctant Promise:** *"Fine, I'll learn your fancy words. BUT - and this is a big BUT - whether you say 'Arrange', 'Setup', 'Given', or 'Pretty-please-configure-my-test', you WILL STILL write descriptive comments! I may have bent on vocabulary, but I will NEVER compromise on quality! Got it, recruit?!"* ๐ŸŽ–๏ธ

*Mutters under breath: "Setup... Given... what's next, 'Lovingly prepare the test environment'? Kids these days..."* ๐Ÿ˜ค

## ๐ŸŽฏ Advanced Usage (Graduate Level)

### Custom Test Structure

```python
# tests/widgets/test_widget_factory.py
# Using the custom mapping from above: DRILL_SERGEANT_MARKER_MAPPINGS="widgets=unit"

def test_widget_creation_with_custom_colors():  # No marker needed! Auto-detected as @pytest.mark.unit
    """Test widget factory creates widgets with specified colors."""
    # Arrange - Prepare the widget factory and color specifications
    factory = WidgetFactory()
    desired_color = Color.NEON_PINK
    expected_widget_count = 1
    
    # Act - Request widget creation with custom color
    created_widgets = factory.create_widgets(
        count=expected_widget_count,
        color=desired_color
    )
    
    # Assert - Verify widget meets specifications
    assert len(created_widgets) == expected_widget_count
    assert created_widgets[0].color == desired_color
    assert created_widgets[0].is_properly_initialized()
```

### Complex AAA with Sub-sections

```python
@pytest.mark.integration
def test_user_authentication_flow():
    """Test complete user authentication including edge cases."""
    # Arrange - Set up test environment and dependencies
    # Database setup
    test_db = create_test_database()
    user_service = UserService(test_db)
    
    # Test user data
    valid_email = "test@example.com"
    valid_password = "SecurePassword123!"
    
    # Mock external services
    email_service = Mock(spec=EmailService)
    
    # Act - Execute the authentication flow
    registration_result = user_service.register_user(
        email=valid_email,
        password=valid_password,
        email_service=email_service
    )
    
    # Assert - Verify all expectations are met
    # Registration success
    assert registration_result.success is True
    assert registration_result.user_id is not None
    
    # Database state
    stored_user = test_db.get_user_by_email(valid_email)
    assert stored_user is not None
    assert stored_user.email == valid_email
    
    # External service interactions
    email_service.send_welcome_email.assert_called_once()
```

## ๐ŸŽช Troubleshooting (When Things Go Wrong)

### "The Drill Sergeant is Too Mean!"

**Problem:** Every test fails with quality violations.  
**Solution:** Your tests actually ARE garbage. Fix them or lower the standards:

```ini
drill_sergeant_enforce_aaa = false  # Give up on structure
drill_sergeant_min_description_length = 1  # Accept "a" as description
```

### "Auto-detection Isn't Working!"

**Problem:** Tests in `tests/unit/` aren't getting `@pytest.mark.unit`.  
**Solution:** Check your directory structure, genius:

```bash
# Wrong (no auto-detection)
tests/
  random_stuff/
    test_unit_something.py

# Right (auto-detects @pytest.mark.unit)
tests/
  unit/
    test_something.py
```

### "I Don't Want Markers!"

**Problem:** You hate organization and progress.  
**Solution:** Turn off marker enforcement:

```ini
drill_sergeant_enforce_markers = false
```

### "The Error Messages Are Too Verbose!"

**Problem:** You don't like helpful feedback.  
**Solution:** There is no solution. Embrace the verbosity. Learn from it. Grow as a developer.

## ๐ŸŽ–๏ธ Contributing (Join the Army)

Want to make the Drill Sergeant even more ruthless? We accept contributions!

### Development Setup

```bash
# Clone the repo (obviously)
git clone https://github.com/jeffrichley/pytest-drill-sergeant.git
cd pytest-drill-sergeant

# Install with development dependencies
uv sync

# Run tests (they better all pass!)
just test

# Check quality (no excuses for sloppy code)
just quality

# See all available commands
just --list
```

### Development Commands

```bash
just test          # Run all tests
just test-unit     # Run only unit tests  
just test-integration  # Run integration tests
just lint          # Check code style
just type-check    # Verify type annotations
just quality       # Run all quality checks
just clean         # Clean up generated files
```

## ๐Ÿ“Š Why This Plugin Exists

**Real talk:** I got tired of reviewing pull requests where tests looked like someone threw code at a wall and hoped it stuck. Tests without markers, no structure, comments like `# test stuff` - it was chaos.

The Drill Sergeant fixes this by:

1. **Making quality automatic** - Can't forget markers if they're added automatically
2. **Teaching good habits** - Clear error messages explain what quality looks like  
3. **Enforcing standards** - No more "we'll fix it later" (spoiler: later never comes)
4. **Being helpful** - Auto-detection means less work for developers who do things right

## ๐ŸŽฏ Philosophy

- **Quality is not negotiable** - Your tests represent your code quality
- **Structure creates clarity** - AAA pattern makes tests readable and maintainable
- **Consistency enables scale** - Markers and structure let teams work together
- **Automation prevents regression** - What can be automated should be automated

## ๐Ÿ”ฎ Future Features (Coming Soonโ„ข)

- **๐ŸŽจ Custom AAA patterns** - Define your own test structure requirements
- **๐Ÿ“Š Quality metrics** - Dashboard showing test quality across your codebase  
- **๐Ÿค– AI-powered suggestions** - Smart recommendations for test improvements
- **๐Ÿ”— IDE integration** - Real-time quality feedback while you type
- **๐Ÿ“ˆ Historical tracking** - See how your test quality improves over time

## ๐Ÿ“œ License

MIT License - Because sharing is caring, and good test quality should be available to everyone.

## ๐ŸŽฏ Final Words

The Drill Sergeant doesn't exist to make your life harder. He exists to make your tests BETTER. 

Better tests = Better code = Better software = Better world.

**Now drop and give me 20 properly structured test cases!** ๐Ÿ’ช

---

*Made with โค๏ธ (and a healthy dose of sarcasm) by developers who care about test quality.*

**P.S.** - If you think this plugin is too strict, wait until you meet Production. The Drill Sergeant is just trying to prepare you for that harsh reality. ๐Ÿ˜ˆ

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "pytest-drill-sergeant",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.12",
    "maintainer_email": null,
    "keywords": "pytest, testing, quality, standards, AAA, markers",
    "author": null,
    "author_email": "Jeff Richley <jeffrichley@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/6a/f5/6be0c10356e2df2f3547ea532b4c3b3a490337a09f4818b178517604a8b3/pytest_drill_sergeant-0.1.0.tar.gz",
    "platform": null,
    "description": "# \ud83c\udf96\ufe0f Pytest Drill Sergeant\n\n<!-- CI/CD Battle Status -->\n[![CI Status](https://github.com/jeffrichley/pytest-drill-sergeant/workflows/CI%20(nox)/badge.svg)](https://github.com/jeffrichley/pytest-drill-sergeant/actions)\n[![codecov](https://codecov.io/gh/jeffrichley/pytest-drill-sergeant/branch/main/graph/badge.svg)](https://codecov.io/gh/jeffrichley/pytest-drill-sergeant)\n[![Quality Gate](https://img.shields.io/badge/quality-A%2B-brightgreen?style=flat&logo=codacy)](https://github.com/jeffrichley/pytest-drill-sergeant)\n\n<!-- Package Battle Metrics -->\n[![PyPI version](https://badge.fury.io/py/pytest-drill-sergeant.svg)](https://badge.fury.io/py/pytest-drill-sergeant)\n[![Python versions](https://img.shields.io/pypi/pyversions/pytest-drill-sergeant.svg)](https://pypi.org/project/pytest-drill-sergeant/)\n[![Downloads](https://pepy.tech/badge/pytest-drill-sergeant)](https://pepy.tech/project/pytest-drill-sergeant)\n\n<!-- Platform Combat Readiness -->\n[![Platforms](https://img.shields.io/badge/platforms-Linux%20%7C%20macOS%20%7C%20Windows-blue)](https://github.com/jeffrichley/pytest-drill-sergeant/actions)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)\n\n<!-- Military Honors & Achievements -->\n[![Tested](https://img.shields.io/badge/battle--tested-6%20environments-red?style=flat&logo=pytest)](https://github.com/jeffrichley/pytest-drill-sergeant/actions)\n[![Type Checked](https://img.shields.io/badge/type--checked-mypy-blue?style=flat&logo=python)](https://github.com/jeffrichley/pytest-drill-sergeant)\n[![Drill Sergeant Approved](https://img.shields.io/badge/drill%20sergeant-approved%20%F0%9F%8E%96%EF%B8%8F-brightgreen)](https://github.com/jeffrichley/pytest-drill-sergeant)\n\n**LISTEN UP, MAGGOTS! \ud83d\udde3\ufe0f**\n\nYour test suite is a DISASTER! Tests scattered everywhere like a tornado hit your codebase, no markers, no structure, and don't even get me started on your \"AAA\" pattern that looks more like \"Aaahhh-what-am-I-even-testing\" pattern.\n\n**The Drill Sergeant is here to whip your tests into shape!** \ud83d\udcaa\n\nThis pytest plugin will turn your chaotic test mess into a disciplined, well-organized military formation. No mercy. No exceptions. Only QUALITY.\n\n## \ud83c\udfc5 Live Battle Intelligence (Auto-Updating Intel)\n\n| **Metric** | **Live Status** | **Military Assessment** |\n|------------|-----------------|-------------------------|\n| **\ud83d\udce6 Codebase Size** | [![Files](https://img.shields.io/github/directory-file-count/jeffrichley/pytest-drill-sergeant/src?label=source%20files&logo=python&color=blue)](https://github.com/jeffrichley/pytest-drill-sergeant) | *\"Lean and mean - no bloat allowed!\"* |\n| **\u2b50 Bug Reports** | [![GitHub issues](https://img.shields.io/github/issues/jeffrichley/pytest-drill-sergeant?label=open%20issues&logo=github)](https://github.com/jeffrichley/pytest-drill-sergeant/issues) | *\"Zero tolerance for battlefield failures!\"* |\n| **\ud83d\udcc8 Activity Level** | [![Commits](https://img.shields.io/github/commit-activity/m/jeffrichley/pytest-drill-sergeant?label=monthly%20commits&logo=git&color=green)](https://github.com/jeffrichley/pytest-drill-sergeant) | *\"Active military operations in progress!\"* |\n| **\u26a1 Response Time** | [![GitHub last commit](https://img.shields.io/github/last-commit/jeffrichley/pytest-drill-sergeant?label=last%20deployment&logo=github-actions)](https://github.com/jeffrichley/pytest-drill-sergeant) | *\"Always ready for action!\"* |\n| **\ud83c\udfaf Stars Earned** | [![GitHub stars](https://img.shields.io/github/stars/jeffrichley/pytest-drill-sergeant?label=stars&logo=github&color=yellow)](https://github.com/jeffrichley/pytest-drill-sergeant) | *\"Recognition from fellow soldiers!\"* |\n\n**The Drill Sergeant's Live Record:** *\"All systems operational, zero compromises accepted!\"* \ud83c\udf96\ufe0f\n\n## \ud83c\udfaf What This Bad Boy Does\n\n- **\ud83c\udff7\ufe0f Automatic Marker Detection** - Because apparently you can't be trusted to add `@pytest.mark.unit` yourself\n- **\ud83d\udcdd AAA Structure Enforcement** - \"Arrange-Act-Assert\" not \"Arrange-Act-And-Hope-It-Works\"  \n- **\ud83d\udca5 Comprehensive Error Messages** - So detailed even your manager could understand what you did wrong\n- **\ud83d\udea8 Zero Tolerance Policy** - One violation = one failed test. NO EXCEPTIONS!\n\n## \ud83d\ude80 Installation (AKA Basic Training)\n\n### For Smart Developers\n\n```bash\n# Development dependency (where it belongs, recruit!)\nuv add --group dev pytest-drill-sergeant\n\n# Or if you're still using that ancient pip thing...\npip install pytest-drill-sergeant\n```\n\n### For \"Special\" Developers\n\n```bash\n# Runtime dependency (really? You need test quality enforcement in production?)\nuv add pytest-drill-sergeant\n```\n\n## \ud83c\udf96\ufe0f Advanced Arsenal (Secret Weapons Unlocked)\n\n[![AAA Structure](https://img.shields.io/badge/AAA-Arrange%20Act%20Assert-blue?style=for-the-badge&logo=checkmarx)](https://github.com/jeffrichley/pytest-drill-sergeant)\n[![Auto Detection](https://img.shields.io/badge/Auto--Detection-16%20Built--in%20Mappings-green?style=for-the-badge&logo=target)](https://github.com/jeffrichley/pytest-drill-sergeant)\n[![Synonyms](https://img.shields.io/badge/Synonyms-Given%2FWhen%2FThen%20Support-purple?style=for-the-badge&logo=language)](https://github.com/jeffrichley/pytest-drill-sergeant)\n[![Zero Config](https://img.shields.io/badge/Zero--Config-Ready%20to%20Deploy-orange?style=for-the-badge&logo=rocket)](https://github.com/jeffrichley/pytest-drill-sergeant)\n\n## \ud83d\udccf Before vs After (Prepare to be AMAZED)\n\n### Before: Your Disaster Zone \ud83d\udd25\n\n```python\n# tests/whatever/test_something.py (what kind of name is that?!)\ndef test_thing():\n    x = Calculator()\n    result = x.add(1, 2)\n    assert result == 3  # Wow, such insight. Much test. Very quality.\n```\n\n**Drill Sergeant says:** *WHAT IS THIS GARBAGE? No marker, no structure, and it's in a random directory! This test FAILS until you fix it!*\n\n### After: PROPER MILITARY FORMATION \ud83c\udf96\ufe0f\n\n```python\n# tests/unit/test_calculator.py (NOW we're talking!)\nimport pytest\n\n@pytest.mark.unit  # AUTOMATIC! The Sergeant detects from directory and adds this! \ud83c\udfaf\ndef test_addition_with_positive_numbers():\n    \"\"\"Test addition functionality with positive integers.\"\"\"\n    # Arrange - Set up your battlefield, soldier!\n    calculator = Calculator()\n    first_operand = 5\n    second_operand = 3\n    expected_sum = 8\n    \n    # Act - Execute the mission!\n    actual_sum = calculator.add(first_operand, second_operand)\n    \n    # Assert - Verify victory conditions!\n    assert actual_sum == expected_sum\n```\n\n**Drill Sergeant says:** *OUTSTANDING! This is what DISCIPLINE looks like!*\n\n### For Simple Tests (One-Liner AAA)\n\nSometimes your test is so simple that combining AAA sections makes sense:\n\n```python\n@pytest.mark.unit\ndef test_simple_calculation():\n    \"\"\"Test basic arithmetic operation.\"\"\"\n    # Arrange and Act - Set up calculator and perform addition\n    result = Calculator().add(2, 3)\n    \n    # Assert - Verify the calculation is correct\n    assert result == 5\n\n@pytest.mark.unit  \ndef test_ultra_simple():\n    \"\"\"Test with all AAA in one comment (for the truly lazy).\"\"\"\n    # Arrange, Act, and Assert - Create, call, and verify in one swift motion\n    assert Calculator().multiply(4, 2) == 8\n```\n\n**Drill Sergeant says:** *Fine, soldier. Sometimes efficiency trumps ceremony. But don't get TOO comfortable!*\n\n## \ud83c\udf96\ufe0f Automatic Marker Detection (Because You're Lazy)\n\nThe Drill Sergeant isn't just here to yell at you - he's here to HELP. Place your tests in the right directories and watch the magic happen:\n\n| Directory | Auto-Applied Marker | What It Means |\n|-----------|-------------------|---------------|\n| `tests/unit/` | `@pytest.mark.unit` | Fast, isolated tests |\n| `tests/integration/` | `@pytest.mark.integration` | Tests multiple components |\n| `tests/e2e/` | `@pytest.mark.e2e` | End-to-end user scenarios |\n| `tests/api/` | `@pytest.mark.integration` | API endpoint tests |\n| `tests/performance/` | `@pytest.mark.performance` | Speed/load tests |\n| `tests/smoke/` | `@pytest.mark.integration` | Quick sanity checks |\n\n**16 built-in mappings** so you don't have to think too hard! \ud83e\udde0  \n*(I've seen you think, and it ain't pretty!)*\n\n### How It Works\n\n1. **You write a test** (hopefully)\n2. **Forget to add a marker** (as usual)  \n3. **Drill Sergeant detects directory** (`tests/unit/test_foo.py`)\n4. **AUTOMATICALLY MODIFIES your test function** to add `@pytest.mark.unit`\n5. **Test passes as if you had added the marker yourself** \ud83c\udfad\n6. **You look competent** (even though the Sergeant did the work)\n\n## \ud83d\udd27 Configuration (For Control Freaks)\n\n### The Nuclear Option: Turn Everything Off\n\n```ini\n# pytest.ini\n[tool:pytest]\ndrill_sergeant_enabled = false\n```\n\n**Drill Sergeant says:** *You're on your own, soldier. Don't come crying when your tests are garbage.*\n\n### Selective Enforcement (Baby Steps)  \n*When you can't handle the full military experience and need training wheels* \ud83d\udeb2\n\n```ini\n# pytest.ini\n[tool:pytest]\ndrill_sergeant_enforce_markers = true      # YES! ENFORCE THE MARKERS!\ndrill_sergeant_enforce_aaa = false         # Fine, be sloppy with your structure\ndrill_sergeant_auto_detect_markers = true  # Let me do your job for you\ndrill_sergeant_min_description_length = 5  # At least TRY to be descriptive\n```\n\n### Custom Mappings (For Special Snowflakes)\n\n```ini\n# pytest.ini\n[tool:pytest]\n# Format: directory_name=marker_name (maps test directories to pytest markers)\ndrill_sergeant_marker_mappings = contract=api,smoke=integration,load=performance\n# Translation for civilians: \n# tests/contract/ \u2192 @pytest.mark.api\n# tests/smoke/ \u2192 @pytest.mark.integration\n# tests/load/ \u2192 @pytest.mark.performance\n```\n\nOr via environment (because you love complexity):\n\n```bash\n# Same format: directory=marker pairs\nexport DRILL_SERGEANT_MARKER_MAPPINGS=\"widget=unit,gizmo=integration\"\n# For those who need it spelled out: \n# tests/widget/ \u2192 @pytest.mark.unit\n# tests/gizmo/ \u2192 @pytest.mark.integration\n```\n\n## \ud83c\udfad Error Messages That Don't Suck\n\nWhen you inevitably mess up, the Drill Sergeant doesn't just say \"test failed\" like some amateur plugin. Oh no. You get the FULL TREATMENT:\n\n```\n\u274c CODE QUALITY: Test 'test_disaster' violates project standards by missing test annotations and missing AAA structure\n\ud83d\udccb 3 requirement(s) must be fixed before this test can run:\n\n\ud83c\udff7\ufe0f  MISSING TEST CLASSIFICATION:\n   \u2022 Add @pytest.mark.unit, @pytest.mark.integration, or move test to appropriate directory structure\n\n\ud83d\udcdd MISSING AAA STRUCTURE (Arrange-Act-Assert):\n   \u2022 Add '# Arrange - description of what is being set up' comment before test setup\n   \u2022 Add '# Act - description of what action is being performed' comment before test action\n\n\u2139\ufe0f  This is a PROJECT REQUIREMENT for all tests to ensure:\n   \u2022 Consistent test structure and readability\n   \u2022 Proper test categorization for CI/CD pipelines\n   \u2022 Maintainable test suite following industry standards\n\n\ud83d\udcda For examples and detailed requirements:\n   \u2022 https://github.com/jeffrichley/pytest-drill-sergeant\n   \u2022 pytest.ini (for valid markers)\n```\n\n**Translation:** *Your test is bad and you should feel bad. Here's exactly how to fix it.*\n\n## \ud83c\udfaa Configuration Examples (Real World Scenarios)\n\n### The \"I'm New Here\" Setup\n\n```ini\n# pytest.ini - Training wheels ON\n[tool:pytest]\ndrill_sergeant_enabled = true\ndrill_sergeant_enforce_markers = false     # Baby steps\ndrill_sergeant_enforce_aaa = true          # Learn structure first\ndrill_sergeant_auto_detect_markers = true  # Let the magic happen\n```\n\n### The \"CI/CD Enforcer\" Setup\n\n```ini\n# pytest.ini - NO MERCY in production\n[tool:pytest]\ndrill_sergeant_enabled = true\ndrill_sergeant_enforce_markers = true      # ZERO TOLERANCE\ndrill_sergeant_enforce_aaa = true          # PERFECT STRUCTURE\ndrill_sergeant_auto_detect_markers = false # Do it yourself, lazy!\n```\n\n### The \"Legacy Codebase Survival\" Setup\n\n```ini\n# pytest.ini - Gradual improvement without mass suicide\n[tool:pytest]\ndrill_sergeant_enabled = true\ndrill_sergeant_enforce_markers = false     # Skip marker enforcement for now\ndrill_sergeant_enforce_aaa = true          # Fix structure first\ndrill_sergeant_auto_detect_markers = true  # Auto-add markers where possible\n```\n\n## \ud83c\udfa8 Environment Variables (For the DevOps Heroes)\n\nControl the Drill Sergeant from your environment like a puppet master:\n\n```bash\n# Turn the drill sergeant into a teddy bear\nexport DRILL_SERGEANT_ENABLED=false\n\n# Make him extra mean about markers\nexport DRILL_SERGEANT_ENFORCE_MARKERS=true\n\n# Demand War and Peace level descriptions\nexport DRILL_SERGEANT_MIN_DESCRIPTION_LENGTH=50\n\n# Custom directory mappings for your special setup\nexport DRILL_SERGEANT_MARKER_MAPPINGS=\"widgets=unit,chaos=stress\"\n```\n\n## \ud83c\udfad AAA Synonym Recognition (Because Apparently You're All Special Snowflakes! \u2744\ufe0f)\n\n### The Problem: \"You're Too Good for Military Vocabulary\" \ud83d\ude24\n\nOh, so the Drill Sergeant's perfectly good vocabulary isn't fancy enough for you? You can't be bothered to learn basic military terminology that's been battle-tested across thousands of codebases? \n\n**Let me guess:**\n- \"Arrange\" is too *corporate* for your hip startup? \ud83d\ude44\n- \"Act\" doesn't capture your *artistic vision* of test methodology? \ud83c\udfa8\n- \"Assert\" sounds too *aggressive* for your safe space codebase? \ud83c\udff3\ufe0f\n\n**Fine. FINE!** The Drill Sergeant will swallow his pride and learn your precious little words. But don't think for a second that lowering his standards to accommodate your delicate sensibilities makes him happy about it.\n\n### The Solution: Synonym Recognition (AKA \"Participation Trophy Mode\") \ud83c\udfc6\n\n*Against his better judgment*, the Sergeant can be taught new vocabulary. He'll grumble about it, but he'll do it. Because apparently \"professional military standards\" aren't good enough for you people.\n\n#### Enable This Madness:\n\n```ini\n# pytest.ini - Enabling the coddling of your fragile vocabulary preferences\n[tool:pytest]\ndrill_sergeant_aaa_synonyms_enabled = true  # *Heavy military sighing* \ud83d\ude2e\u200d\ud83d\udca8\n```\n\n#### Built-in Synonyms (Because I Apparently Have to Do Everything for You):\n\n**Arrange Synonyms:** Setup, Given, Prepare, Initialize, Configure, Create, Build  \n*\"Setup? SETUP?! It's called ARRANGE! But sure, let's use baby words...\"*\n\n**Act Synonyms:** Call, Execute, Run, Invoke, Perform, Trigger, When  \n*\"I suppose 'When' is more gentle than 'Act'. Wouldn't want to trigger anyone...\"*\n\n**Assert Synonyms:** Verify, Check, Expect, Validate, Confirm, Ensure, Then  \n*\"Oh, we can't 'Assert' things anymore? Too confrontational? My mistake, let's 'gently verify'...\"*\n\n#### Now These ALL Work! (God Help Us All) \ud83c\udf89\n\n```python\ndef test_user_authentication():\n    # Setup user credentials and mock database\n    user = User(username=\"test_user\")\n    \n    # Call the authentication service \n    result = auth_service.authenticate(user.username, \"password123\")\n    \n    # Verify successful authentication\n    assert result.success is True\n```\n\n**Drill Sergeant internal monologue:** *\"'Setup'... 'Call'... 'Verify'... What's next, 'Pretty please test my code'? In my day, we had STANDARDS! But nooooo, everyone's a special butterfly with their own vocabulary...\"* \ud83e\udd8b\n\n```python  \ndef test_bdd_style():\n    # Given a valid shopping cart with items\n    cart = ShoppingCart()\n    cart.add_item(\"widget\", price=10.00)\n    \n    # When calculating the total price\n    total = cart.calculate_total()\n    \n    # Then the result should include tax\n    assert total == 10.80  # 8% tax included\n```\n\n**Drill Sergeant:** *\"Oh look, BDD! 'Given/When/Then' - how PRECIOUS! Let me guess, you also use 'user stories' instead of requirements and call bugs 'opportunities for improvement'? Next you'll want me to validate your feelings instead of your code!\"* \ud83d\udc85\n\n#### Custom Synonyms (For Extra Special Snowflakes):\n\nOh, the built-in synonyms aren't unique enough for you? You need your OWN PERSONAL vocabulary? Of course you do. \ud83d\ude44\n\n```ini\n# pytest.ini - Because you're just THAT special\ndrill_sergeant_aaa_arrange_synonyms = Background,Precondition,Setup\ndrill_sergeant_aaa_act_synonyms = Execute,Trigger,Action  \ndrill_sergeant_aaa_assert_synonyms = Expect,Outcome,Result\n```\n\n*\"Let me guess - your team is 'different' and 'innovative' and needs custom words to express your unique testing philosophy? Can't just use the same words as literally everyone else in the industry?\"*\n\n```python\ndef test_with_custom_vocabulary():\n    # Background - Configure the test environment  \n    api_client = APIClient(base_url=\"https://test.api.com\")\n    \n    # Execute - Trigger the user creation endpoint\n    response = api_client.create_user({\"name\": \"John\", \"email\": \"john@test.com\"})\n    \n    # Expect - Result should be successful user creation\n    assert response.status_code == 201\n    assert response.json()[\"user\"][\"name\"] == \"John\"\n```\n\n**Drill Sergeant:** *\"'Background'? 'Execute'? 'Expect'? What are you, writing poetry? It's a TEST, not a haiku! But fine, I'll learn your artisanal vocabulary. Just don't expect me to like it.\"* \ud83d\udcdd\n\n#### Environment Variable Control (For the Control Freaks):\n\nBecause apparently config files are too mainstream for you? You need ENVIRONMENT VARIABLES? \ud83c\udf0d\n\n```bash\n# Enable this circus of accommodation\nexport DRILL_SERGEANT_AAA_SYNONYMS_ENABLED=true\n\n# Reject all my hard work and use only your precious custom words\nexport DRILL_SERGEANT_AAA_BUILTIN_SYNONYMS=false\n\n# Define your team's \"unique\" vocabulary (eye roll intensifies)\nexport DRILL_SERGEANT_AAA_ARRANGE_SYNONYMS=\"Setup,Given,Background\"\nexport DRILL_SERGEANT_AAA_ACT_SYNONYMS=\"When,Call,Execute\"\nexport DRILL_SERGEANT_AAA_ASSERT_SYNONYMS=\"Then,Verify,Check\"\n```\n\n*\"Oh sure, let's make it even MORE complicated! Why have one place to configure things when you can have seventeen different ways? This is why we can't have nice things.\"* \ud83e\udd26\u200d\u2642\ufe0f\n\n#### Backward Compatibility (Because I'm Not a Complete Monster): \u2705\n\nLook, I may be bitter about this whole \"synonym accommodation\" situation, but I'm not going to break your existing code. I have SOME integrity left.\n\n- **Default: DISABLED** - Because I refuse to enable this madness by default\n- **Original keywords always work** - \"Arrange/Act/Assert\" will NEVER be deprecated (unlike my dignity)\n- **Explicit opt-in** - You have to ASK for this nonsense explicitly\n- **Layered configuration** - Environment variables override pytest.ini because apparently you need 47 ways to configure everything\n\n**The Drill Sergeant's Reluctant Promise:** *\"Fine, I'll learn your fancy words. BUT - and this is a big BUT - whether you say 'Arrange', 'Setup', 'Given', or 'Pretty-please-configure-my-test', you WILL STILL write descriptive comments! I may have bent on vocabulary, but I will NEVER compromise on quality! Got it, recruit?!\"* \ud83c\udf96\ufe0f\n\n*Mutters under breath: \"Setup... Given... what's next, 'Lovingly prepare the test environment'? Kids these days...\"* \ud83d\ude24\n\n## \ud83c\udfaf Advanced Usage (Graduate Level)\n\n### Custom Test Structure\n\n```python\n# tests/widgets/test_widget_factory.py\n# Using the custom mapping from above: DRILL_SERGEANT_MARKER_MAPPINGS=\"widgets=unit\"\n\ndef test_widget_creation_with_custom_colors():  # No marker needed! Auto-detected as @pytest.mark.unit\n    \"\"\"Test widget factory creates widgets with specified colors.\"\"\"\n    # Arrange - Prepare the widget factory and color specifications\n    factory = WidgetFactory()\n    desired_color = Color.NEON_PINK\n    expected_widget_count = 1\n    \n    # Act - Request widget creation with custom color\n    created_widgets = factory.create_widgets(\n        count=expected_widget_count,\n        color=desired_color\n    )\n    \n    # Assert - Verify widget meets specifications\n    assert len(created_widgets) == expected_widget_count\n    assert created_widgets[0].color == desired_color\n    assert created_widgets[0].is_properly_initialized()\n```\n\n### Complex AAA with Sub-sections\n\n```python\n@pytest.mark.integration\ndef test_user_authentication_flow():\n    \"\"\"Test complete user authentication including edge cases.\"\"\"\n    # Arrange - Set up test environment and dependencies\n    # Database setup\n    test_db = create_test_database()\n    user_service = UserService(test_db)\n    \n    # Test user data\n    valid_email = \"test@example.com\"\n    valid_password = \"SecurePassword123!\"\n    \n    # Mock external services\n    email_service = Mock(spec=EmailService)\n    \n    # Act - Execute the authentication flow\n    registration_result = user_service.register_user(\n        email=valid_email,\n        password=valid_password,\n        email_service=email_service\n    )\n    \n    # Assert - Verify all expectations are met\n    # Registration success\n    assert registration_result.success is True\n    assert registration_result.user_id is not None\n    \n    # Database state\n    stored_user = test_db.get_user_by_email(valid_email)\n    assert stored_user is not None\n    assert stored_user.email == valid_email\n    \n    # External service interactions\n    email_service.send_welcome_email.assert_called_once()\n```\n\n## \ud83c\udfaa Troubleshooting (When Things Go Wrong)\n\n### \"The Drill Sergeant is Too Mean!\"\n\n**Problem:** Every test fails with quality violations.  \n**Solution:** Your tests actually ARE garbage. Fix them or lower the standards:\n\n```ini\ndrill_sergeant_enforce_aaa = false  # Give up on structure\ndrill_sergeant_min_description_length = 1  # Accept \"a\" as description\n```\n\n### \"Auto-detection Isn't Working!\"\n\n**Problem:** Tests in `tests/unit/` aren't getting `@pytest.mark.unit`.  \n**Solution:** Check your directory structure, genius:\n\n```bash\n# Wrong (no auto-detection)\ntests/\n  random_stuff/\n    test_unit_something.py\n\n# Right (auto-detects @pytest.mark.unit)\ntests/\n  unit/\n    test_something.py\n```\n\n### \"I Don't Want Markers!\"\n\n**Problem:** You hate organization and progress.  \n**Solution:** Turn off marker enforcement:\n\n```ini\ndrill_sergeant_enforce_markers = false\n```\n\n### \"The Error Messages Are Too Verbose!\"\n\n**Problem:** You don't like helpful feedback.  \n**Solution:** There is no solution. Embrace the verbosity. Learn from it. Grow as a developer.\n\n## \ud83c\udf96\ufe0f Contributing (Join the Army)\n\nWant to make the Drill Sergeant even more ruthless? We accept contributions!\n\n### Development Setup\n\n```bash\n# Clone the repo (obviously)\ngit clone https://github.com/jeffrichley/pytest-drill-sergeant.git\ncd pytest-drill-sergeant\n\n# Install with development dependencies\nuv sync\n\n# Run tests (they better all pass!)\njust test\n\n# Check quality (no excuses for sloppy code)\njust quality\n\n# See all available commands\njust --list\n```\n\n### Development Commands\n\n```bash\njust test          # Run all tests\njust test-unit     # Run only unit tests  \njust test-integration  # Run integration tests\njust lint          # Check code style\njust type-check    # Verify type annotations\njust quality       # Run all quality checks\njust clean         # Clean up generated files\n```\n\n## \ud83d\udcca Why This Plugin Exists\n\n**Real talk:** I got tired of reviewing pull requests where tests looked like someone threw code at a wall and hoped it stuck. Tests without markers, no structure, comments like `# test stuff` - it was chaos.\n\nThe Drill Sergeant fixes this by:\n\n1. **Making quality automatic** - Can't forget markers if they're added automatically\n2. **Teaching good habits** - Clear error messages explain what quality looks like  \n3. **Enforcing standards** - No more \"we'll fix it later\" (spoiler: later never comes)\n4. **Being helpful** - Auto-detection means less work for developers who do things right\n\n## \ud83c\udfaf Philosophy\n\n- **Quality is not negotiable** - Your tests represent your code quality\n- **Structure creates clarity** - AAA pattern makes tests readable and maintainable\n- **Consistency enables scale** - Markers and structure let teams work together\n- **Automation prevents regression** - What can be automated should be automated\n\n## \ud83d\udd2e Future Features (Coming Soon\u2122)\n\n- **\ud83c\udfa8 Custom AAA patterns** - Define your own test structure requirements\n- **\ud83d\udcca Quality metrics** - Dashboard showing test quality across your codebase  \n- **\ud83e\udd16 AI-powered suggestions** - Smart recommendations for test improvements\n- **\ud83d\udd17 IDE integration** - Real-time quality feedback while you type\n- **\ud83d\udcc8 Historical tracking** - See how your test quality improves over time\n\n## \ud83d\udcdc License\n\nMIT License - Because sharing is caring, and good test quality should be available to everyone.\n\n## \ud83c\udfaf Final Words\n\nThe Drill Sergeant doesn't exist to make your life harder. He exists to make your tests BETTER. \n\nBetter tests = Better code = Better software = Better world.\n\n**Now drop and give me 20 properly structured test cases!** \ud83d\udcaa\n\n---\n\n*Made with \u2764\ufe0f (and a healthy dose of sarcasm) by developers who care about test quality.*\n\n**P.S.** - If you think this plugin is too strict, wait until you meet Production. The Drill Sergeant is just trying to prepare you for that harsh reality. \ud83d\ude08\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A pytest plugin that enforces test quality standards through automatic marker detection and AAA structure validation",
    "version": "0.1.0",
    "project_urls": {
        "Homepage": "https://github.com/jeffrichley/pytest-drill-sergeant",
        "Issues": "https://github.com/jeffrichley/pytest-drill-sergeant/issues",
        "Repository": "https://github.com/jeffrichley/pytest-drill-sergeant.git"
    },
    "split_keywords": [
        "pytest",
        " testing",
        " quality",
        " standards",
        " aaa",
        " markers"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "77f9add86d154e433a4f4175ae0d20ed1a0134ba67bce059bfdf752c95a7096b",
                "md5": "dddb40b1f207532c62fba9856348d591",
                "sha256": "69eee28d5caa9c9d6d363f2bb2e88d0955dfcbd0d0dd9e25e032474031a5d3e5"
            },
            "downloads": -1,
            "filename": "pytest_drill_sergeant-0.1.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "dddb40b1f207532c62fba9856348d591",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.12",
            "size": 19378,
            "upload_time": "2025-09-02T20:37:20",
            "upload_time_iso_8601": "2025-09-02T20:37:20.918483Z",
            "url": "https://files.pythonhosted.org/packages/77/f9/add86d154e433a4f4175ae0d20ed1a0134ba67bce059bfdf752c95a7096b/pytest_drill_sergeant-0.1.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "6af56be0c10356e2df2f3547ea532b4c3b3a490337a09f4818b178517604a8b3",
                "md5": "8fa4e6790cbdd820b1759afe441c5017",
                "sha256": "f93df95cfe75b616b6208c103971be3450d82b18f5d0e2e4f3e52b1a307bf28c"
            },
            "downloads": -1,
            "filename": "pytest_drill_sergeant-0.1.0.tar.gz",
            "has_sig": false,
            "md5_digest": "8fa4e6790cbdd820b1759afe441c5017",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.12",
            "size": 30090,
            "upload_time": "2025-09-02T20:37:21",
            "upload_time_iso_8601": "2025-09-02T20:37:21.911850Z",
            "url": "https://files.pythonhosted.org/packages/6a/f5/6be0c10356e2df2f3547ea532b4c3b3a490337a09f4818b178517604a8b3/pytest_drill_sergeant-0.1.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-09-02 20:37:21",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "jeffrichley",
    "github_project": "pytest-drill-sergeant",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "pytest-drill-sergeant"
}
        
Elapsed time: 0.60778s