system-prompts-and-models-o.../salesflow-saas/.claude/commands/generate-tests.md
Claude 83210b9d12
feat: Add founder strategy, Claude Code control plane, SaaS launch readiness
Founder Strategy & GTM (from prompts #1, #10):
- niche-brief.md: Saudi real estate primary, healthcare secondary
- icp-brief.md: Full ICP with Arabic objection handling
- content-map.md: 20 content ideas, SEO keywords, weekly schedule
- outreach-map.md: WhatsApp/Email cold outreach with Arabic templates
- launch-plan.md: 14-day sprint + 30-day plan with revenue targets
- interview-template.md: 15 Arabic customer discovery questions

Claude Code Control Plane (from prompt #2):
- .claude/settings.json: Permissions and preferences
- .claude/commands/: 5 custom commands (review-pr, release-prep, security-check, generate-tests, architecture-review)
- .claude/hooks/: pre-commit.sh (secrets check), pre-push.sh (tests)

SaaS Launch Readiness (from prompt #4):
- saas-readiness-audit.md: Full audit with gap analysis
- deployment-checklist.md: Deploy + rollback procedures
- launch-checklist.md: 100+ launch day checklist items
- feature_flags.py: Redis-backed feature flags with per-tenant control

https://claude.ai/code/session_01LsnvBa7HwF5hs99VZbgLGj
2026-04-11 08:09:50 +00:00

131 lines
4.0 KiB
Markdown

# /generate-tests — Auto-generate Tests for Dealix Services
Analyze a service file and generate comprehensive pytest-asyncio tests with factory-boy fixtures.
## Usage
Provide the path to a service file, e.g.: `/generate-tests backend/app/services/lead_service.py`
## Steps
### 1. Analyze the Target Service
Read the specified service file and extract:
- Class name and constructor dependencies (db session, other services)
- All public methods with their signatures and return types
- Database models referenced
- External service calls (WhatsApp, email, Stripe, AI providers)
- Async vs sync methods
### 2. Identify Test Cases
For each public method, generate tests for:
- **Happy path** — normal operation with valid inputs
- **Empty/null input** — None, empty string, empty list
- **Invalid tenant** — wrong tenant_id, missing tenant_id
- **Not found** — entity does not exist
- **Duplicate** — creating something that already exists
- **Permission denied** — user lacks required role
- **Boundary values** — max length strings, zero amounts, negative numbers
- **Concurrent access** — if method modifies shared state
### 3. Generate Factory Classes
Create factory-boy factories for each model used:
```python
import factory
from factory.alchemy import SQLAlchemyModelFactory
class TenantFactory(SQLAlchemyModelFactory):
class Meta:
model = Tenant
sqlalchemy_session_persistence = "commit"
id = factory.LazyFunction(uuid4)
name = factory.Faker("company", locale="ar_SA")
domain = factory.Faker("domain_name")
is_active = True
created_at = factory.LazyFunction(lambda: datetime.now(timezone.utc))
```
Use `locale="ar_SA"` for Arabic data where appropriate (names, companies, addresses).
### 4. Generate Test File
Create the test file at `backend/tests/test_services/test_<service_name>.py` with:
```python
"""
Tests for <ServiceName>.
Auto-generated — review and customize before committing.
"""
import pytest
from unittest.mock import AsyncMock, MagicMock, patch
from uuid import uuid4
from app.services.<module> import <ServiceClass>
@pytest.fixture
def db_session():
"""Mock async database session."""
session = AsyncMock()
session.execute = AsyncMock()
session.commit = AsyncMock()
session.rollback = AsyncMock()
session.refresh = AsyncMock()
return session
@pytest.fixture
def service(db_session):
return <ServiceClass>(db=db_session)
@pytest.fixture
def tenant_id():
return uuid4()
class TestMethodName:
@pytest.mark.asyncio
async def test_success(self, service, tenant_id):
# Arrange
...
# Act
result = await service.method_name(...)
# Assert
assert result is not None
@pytest.mark.asyncio
async def test_not_found(self, service, tenant_id):
service.db.execute.return_value = MagicMock(scalar_one_or_none=MagicMock(return_value=None))
with pytest.raises(NotFoundException):
await service.method_name(...)
@pytest.mark.asyncio
async def test_wrong_tenant(self, service):
wrong_tenant = uuid4()
# Should not return data from another tenant
...
```
### 5. Mocking Strategy
- **Database**: Mock `AsyncSession` with `execute()` returning mock results
- **Redis**: Mock with `fakeredis.aioredis` or `AsyncMock`
- **External APIs** (WhatsApp, Stripe): Use `unittest.mock.patch` on the service method
- **Celery tasks**: Mock with `@patch("app.workers.task_name.delay")`
- **AI services**: Mock LLM responses with fixed JSON structures
- **Time-dependent**: Use `freezegun` for timestamp-sensitive logic
### 6. Validation Checklist
After generating, verify:
- [ ] All public methods have at least one test
- [ ] Async methods use `@pytest.mark.asyncio`
- [ ] Mocks match actual method signatures
- [ ] Tenant isolation is tested
- [ ] No real external calls in tests
- [ ] Test file runs without import errors: `pytest <test_file> --co -q`
### 7. Output
Print the complete test file content and the command to run it:
```bash
pytest backend/tests/test_services/test_<name>.py -v
```