Agent skill
testing-core
Cross-language testing patterns: unit, integration, E2E testing strategies. Use when: writing tests, setting up test infrastructure, or improving coverage. Triggers: "test", "testing", "unit test", "integration test", "e2e", "coverage", "mock", "fixture".
Install this agent skill to your Project
npx add-skill https://github.com/timequity/vibe-coder/tree/main/skills/testing-core
SKILL.md
Testing Core
Quick Reference
| Topic | Reference |
|---|---|
| Mocking | mocking.md — Python, TypeScript, Rust mocking patterns |
Test Pyramid
/ E2E \ Few, slow, expensive
/─────────\
/ Integration \ Some, medium speed
/───────────────\
/ Unit \ Many, fast, cheap
/─────────────────────\
When to Use Each
| Type | Tests What | Speed | When |
|---|---|---|---|
| Unit | Single function/class | Fast | Pure logic, calculations |
| Integration | Components together | Medium | DB queries, API calls |
| E2E | Full user flow | Slow | Critical paths only |
Test Structure (AAA)
def test_user_creation():
# Arrange - Setup test data
user_data = {"email": "test@example.com", "name": "Test"}
# Act - Execute the code
user = user_service.create(user_data)
# Assert - Verify results
assert user.email == "test@example.com"
assert user.id is not None
Naming Convention
test_<what>_<scenario>_<expected>
# Examples:
test_create_user_valid_data_returns_user()
test_create_user_duplicate_email_raises_error()
test_get_user_not_found_returns_none()
Unit Test Patterns
Testing Pure Functions
# Function
def calculate_discount(price: float, percentage: float) -> float:
return price * (1 - percentage / 100)
# Test
def test_calculate_discount():
assert calculate_discount(100, 10) == 90
assert calculate_discount(50, 50) == 25
assert calculate_discount(100, 0) == 100
Testing Edge Cases
@pytest.mark.parametrize("input,expected", [
("", False), # Empty
("a@b.c", True), # Minimal valid
("test@example.com", True),
("invalid", False), # No @
("@example.com", False), # No local part
("test@", False), # No domain
])
def test_validate_email(input, expected):
assert validate_email(input) == expected
Testing Exceptions
def test_divide_by_zero_raises():
with pytest.raises(ZeroDivisionError):
divide(10, 0)
def test_invalid_input_raises_with_message():
with pytest.raises(ValueError) as exc_info:
process_data(None)
assert "cannot be None" in str(exc_info.value)
Integration Test Patterns
Database Tests
@pytest.fixture
async def db_session():
# Setup
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
async with AsyncSession(engine) as session:
yield session
# Teardown
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.drop_all)
async def test_create_and_fetch_user(db_session):
# Create
user = User(email="test@example.com", name="Test")
db_session.add(user)
await db_session.commit()
# Fetch
result = await db_session.get(User, user.id)
assert result.email == "test@example.com"
API Tests
async def test_api_create_user(client):
response = await client.post(
"/users",
json={"email": "test@example.com", "name": "Test"}
)
assert response.status_code == 201
data = response.json()
assert data["email"] == "test@example.com"
assert "id" in data
Mocking Patterns
When to Mock
Mock:
├─ External APIs (payment, email, SMS)
├─ Time/dates (for deterministic tests)
├─ Random values
└─ Slow operations
Don't Mock:
├─ The code you're testing
├─ Simple data structures
└─ Things you can use real instances of
Mock Examples
# Python
from unittest.mock import Mock, patch, AsyncMock
@patch("services.email.send_email")
def test_signup_sends_email(mock_send):
mock_send.return_value = True
signup("test@example.com")
mock_send.assert_called_once_with("test@example.com", subject=ANY)
# Async mock
@patch("services.payment.charge", new_callable=AsyncMock)
async def test_checkout(mock_charge):
mock_charge.return_value = {"id": "ch_123"}
result = await checkout(cart)
assert result.payment_id == "ch_123"
// TypeScript (Vitest)
import { vi } from 'vitest';
vi.mock('./email', () => ({
sendEmail: vi.fn().mockResolvedValue(true)
}));
test('signup sends email', async () => {
await signup('test@example.com');
expect(sendEmail).toHaveBeenCalledWith('test@example.com', expect.any(String));
});
Fixtures & Factories
Fixture Pattern
@pytest.fixture
def user():
return User(id=1, email="test@example.com", name="Test")
@pytest.fixture
def admin_user(user):
user.role = "admin"
return user
def test_with_fixtures(user, admin_user):
assert user.role != "admin"
assert admin_user.role == "admin"
Factory Pattern
def create_user(**overrides):
defaults = {
"email": f"test-{uuid4()}@example.com",
"name": "Test User",
"role": "user"
}
return User(**{**defaults, **overrides})
def test_with_factory():
user = create_user(role="admin")
assert user.role == "admin"
Coverage Goals
| Type | Target | Notes |
|---|---|---|
| Unit tests | 80%+ | Focus on logic |
| Integration | Key paths | DB operations, APIs |
| E2E | Critical flows | Signup, checkout |
What NOT to Test
- Framework code (it's already tested)
- Trivial getters/setters
- Third-party libraries
- Generated code
Smoke Tests (CRITICAL)
Smoke tests verify the app actually starts and responds. Unit tests can pass while the app is completely broken.
Why Smoke Tests Matter
Scenario: All unit tests pass, app doesn't start
Unit tests:
✓ test_create_user_returns_user
✓ test_delete_user_removes_from_db
✓ test_list_users_returns_all
Reality:
$ cargo run
Error: main.rs missing or broken
Smoke Test Pattern (Rust/Axum)
// REQUIRED: Every project needs this test
#[tokio::test]
async fn test_health_check_responds() {
let server = TestServer::new(create_app()).unwrap();
let response = server.get("/health").await;
response.assert_status_ok();
}
Smoke Tests for Fullstack (HTMX)
#[tokio::test]
async fn test_index_page_is_usable() {
let server = TestServer::new(create_app()).unwrap();
let response = server.get("/").await;
let html = response.text();
// Page loads
assert!(html.contains("<!DOCTYPE html>"));
// Has create form
assert!(html.contains("hx-post"), "Must have HTMX form");
// Has submit button
assert!(html.contains(r#"type="submit""#));
}
Verification Gate Smoke Test
The verify.py script automatically:
- Builds the app (
cargo build) - Starts it (
cargo run) - Waits for
/healthto respond - Fails if app doesn't start within 10 seconds
Anti-patterns
| Don't | Do Instead |
|---|---|
| Test implementation details | Test behavior |
| Duplicate prod logic in tests | Use different approach |
| Flaky tests | Fix or delete |
| Test everything | Test what matters |
| Mock everything | Use real when possible |
| Giant test functions | Small, focused tests |
| Skip smoke tests | Always test app starts |
| Skip UI presence tests | Verify forms/buttons exist |
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
mvp-help
Help and documentation for Idea to MVP plugin. Use when: user asks about building MVPs, vibe coding, or available commands. Triggers: "help", "what can you do", "mvp help", "how to build".
verification-gate
Hidden quality gate that runs before showing "Done!" to user - ensures all tests pass, build succeeds, and requirements met before claiming completion
brainstorming
Refine ideas into detailed designs through Socratic dialogue. Use when: user has rough idea, needs to clarify requirements, explore approaches. Triggers: "brainstorm", "discuss idea", "I'm thinking about", "what if", "help me think through", "explore options", "/brainstorm".
subagent-creator
Guide for creating effective subagents (custom agents). Use when users want to create a new subagent that can be dispatched via Task tool for autonomous work. Covers frontmatter fields (name, description, tools, model, permissionMode, skills), prompt design, and when to use subagents vs skills.
backend-rust
Modern Rust backend with Axum, SQLx, tokio + CI/CD automation. Use when: building Rust APIs, high-performance services, or needing build/test/lint/audit automation. Triggers: "axum", "rust backend", "rust api", "sqlx", "tokio", "cargo build", "cargo test", "clippy", "rustfmt", "cargo-audit", "cross-compile", "rust ci", "release build", "rust security", "shuttle", "actix".
test-driven-development
Write failing test first, then minimal code to pass. Red-Green-Refactor cycle. Use when: implementing features, fixing bugs, refactoring code. Triggers: "implement", "add feature", "fix bug", "tdd", "test first", "write tests", "test-driven".
Didn't find tool you were looking for?