Agent skill
local-service-testing
Use when code changes touch database, cache, queue, or other service-dependent components - enforces testing against real local services instead of mocks
Install this agent skill to your Project
npx add-skill https://github.com/troykelly/codex-skills/tree/main/skills/local-service-testing
SKILL.md
Local Service Testing
Overview
Test against real services locally before pushing. CI validates—it doesn't discover.
Core principle: If you mock what you can run locally, you're hiding bugs.
Announce at start: "I'm using local-service-testing to verify changes against real services."
The Iron Law
CI DISCOVERS NOTHING.
IF CI FINDS A BUG, YOUR LOCAL TESTING FAILED.
Local services exist for a reason. Use them.
Critical Clarification
Unit tests with mocks: REQUIRED (for TDD cycle) Integration tests with real services: ALSO REQUIRED
This skill does NOT replace mocking in unit tests. It ADDS the requirement for integration tests against real services. Both are mandatory.
When This Skill Applies
| Code Change | Required Service | Must Test Against |
|---|---|---|
| Database models/entities | postgres | Real postgres |
| Migrations | postgres | Real postgres |
| Repository/ORM layer | postgres | Real postgres |
| SQL queries | postgres | Real postgres |
| Cache operations | redis | Real redis |
| Session storage | redis | Real redis |
| Pub/sub messages | redis/rabbitmq | Real queue |
| Queue workers | redis/rabbitmq | Real queue |
| API endpoints | all services | All running |
If your change touches any of these, you MUST test against the real service.
Service Detection
At session start, the session-start.sh hook reports available services:
Checking development services...
✓ Found docker-compose.yml
Available services:
✓ postgres (running)
○ redis (not running)
Tip: Start services with: docker-compose up -d
Starting Services
# Start all services
docker-compose up -d
# Start specific service
docker-compose up -d postgres
# Check status
docker-compose ps
Service Connection Strings
| Service | Default Connection |
|---|---|
| postgres | postgresql://localhost:5432/dev |
| redis | redis://localhost:6379 |
| rabbitmq | amqp://localhost:5672 |
Check your project's .env.example or docker-compose.yml for actual values.
Testing Protocol
Step 1: Identify Service Dependencies
Before testing, identify which services your changes require:
# Check what files you've changed
git diff --name-only HEAD~1
# Map to services:
# *.sql, *migration*, *model*, *entity*, *repository* → postgres
# *cache*, *redis*, *session*, *queue*, *pub*, *sub* → redis
# *worker*, *job*, *consumer* → queue service
Step 2: Ensure Services Running
# Start required services
docker-compose up -d postgres redis
# Verify they're ready
docker-compose ps
# Test connectivity
# Postgres
psql postgresql://localhost:5432/dev -c "SELECT 1"
# Redis
redis-cli ping
Step 3: Run Integration Tests
# Run integration tests (not unit tests with mocks)
pnpm test:integration
# Or run specific integration test suite
pnpm test --grep "integration"
# For Python projects
pytest tests/integration/
# For Go projects
go test -tags=integration ./...
Step 4: Verify Locally Before Pushing
Before git push:
# Full verification
pnpm build
pnpm lint
pnpm typecheck
pnpm test # Unit tests
pnpm test:integration # Integration tests against real services
Two-Layer Testing Requirement
Both Are Required
| Test Layer | Purpose | Uses Mocks? | Uses Real Services? | Required? |
|---|---|---|---|---|
| Unit tests | TDD cycle, verify logic | YES | No | YES |
| Integration tests | Verify real behavior | No | YES | YES |
Why Both?
- Unit tests with mocks: Fast, enable RED-GREEN-REFACTOR, isolate logic
- Integration tests with services: Catch real-world failures mocks miss
We've experienced 80% failure rates with ORM migrations because unit tests with mocks passed but real databases rejected the changes.
What Mocks Miss
// Mock says this works
const mockDb = {
query: jest.fn().mockResolvedValue([{ id: 1 }])
};
// But real postgres throws:
// ERROR: relation "users" does not exist
// ERROR: column "email" cannot be null
// ERROR: duplicate key violates unique constraint
Real services reveal:
- Schema mismatches
- Constraint violations
- Connection issues
- Transaction behavior
- Performance problems
Artifact Requirement
Before creating a PR, you must post local testing evidence to the issue.
Required Artifact Format
<!-- LOCAL-TESTING:START -->
## Local Service Testing
| Service | Status | Verification |
|---------|--------|--------------|
| postgres | ✅ Running | Migrations applied, queries executed |
| redis | ✅ Running | Cache operations verified |
**Tests Run:**
- `pnpm test:integration` - PASSED
- Manual verification of [specific feature]
**Tested At:** 2025-01-15T10:30:00Z
<!-- LOCAL-TESTING:END -->
Where to Post
Post as a comment on the GitHub issue you're working on. This is checked by the validate-local-testing.sh PreToolUse hook before PR creation.
When Artifact is Required
The hook checks:
- Does docker-compose.yml exist?
- Do changed files match service patterns?
- If yes to both → artifact required
If no services are relevant to your changes, no artifact is needed.
Common Patterns
Database Testing
// GOOD: Test against real postgres
describe('UserRepository (integration)', () => {
beforeAll(async () => {
await db.migrate.latest();
});
afterAll(async () => {
await db.destroy();
});
it('creates user with unique email constraint', async () => {
await userRepo.create({ email: 'test@example.com' });
// Real postgres will throw on duplicate
await expect(
userRepo.create({ email: 'test@example.com' })
).rejects.toThrow(/unique constraint/);
});
});
Cache Testing
// GOOD: Test against real redis
describe('CacheService (integration)', () => {
beforeEach(async () => {
await redis.flushdb();
});
it('expires keys after TTL', async () => {
await cache.set('key', 'value', { ttl: 1 });
expect(await cache.get('key')).toBe('value');
await sleep(1100);
expect(await cache.get('key')).toBeNull();
});
});
API Testing
// GOOD: Test against real services
describe('POST /users (integration)', () => {
it('creates user and caches result', async () => {
const response = await request(app)
.post('/users')
.send({ email: 'new@example.com' });
expect(response.status).toBe(201);
// Verify in real database
const user = await db('users').where({ email: 'new@example.com' }).first();
expect(user).toBeDefined();
// Verify in real cache
const cached = await redis.get(`user:${user.id}`);
expect(cached).toBeDefined();
});
});
Troubleshooting
| Problem | Solution |
|---|---|
| Service not starting | Check docker-compose logs [service] |
| Connection refused | Ensure service is running and port is correct |
| Database doesn't exist | Run migrations: pnpm migrate |
| Tests pass locally, fail in CI | Environment variable mismatch—check .env vs CI config |
| Flaky integration tests | Check for proper test isolation and cleanup |
Checklist
Before creating PR:
- Identified all service dependencies for changes
- All required services are running locally
- Integration tests pass against real services
- Posted local testing artifact to issue
- Did not rely on mocks for service-dependent code
Integration
This skill is called by:
tdd-full-coverage- For integration testing requirementsissue-driven-development- Before PR creationverification-before-merge- As a merge gate
This skill is enforced by:
validate-local-testing.sh- PreToolUse hook blocks PR without artifact
This skill references:
environment-bootstrap- For service startup patternssession-start- For service detection at session start
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
hook-development
Use when the user wants to create Codex workflow hooks (pre/post run gates, tool-use validators, stop checks) or needs guidance on hook scripts and hooks.json configuration.
sentry-setup-ai-monitoring
Setup Sentry AI Agent Monitoring in any project. Use this when asked to add AI monitoring, track LLM calls, monitor AI agents, or instrument OpenAI/Anthropic/Vercel AI/LangChain/Google GenAI. Automatically detects installed AI SDKs and configures the appropriate Sentry integration.
agent-development
Use when the user wants to design Codex agent equivalents (specialized workers/profiles/prompt files), define triggering conditions, or build reusable agent prompts and validation tools.
skill-development
Use when the user wants to create or refine Codex skills, improve skill descriptions, organize skill resources, or follow Codex skill best practices.
sentry-setup-logging
Setup Sentry Logging in any project. Use this when asked to add Sentry logs, enable structured logging, setup console log capture, or integrate logging with Sentry. Supports JavaScript, TypeScript, Python, Ruby, React, Next.js, and other frameworks.
frontend-design
Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
Didn't find tool you were looking for?