From claude-initial-setup
Test organization, fixtures, factories (factory_boy/faker), test isolation, database cleanup, and test configuration. Use when the user is setting up a test suite, organizing test files, creating test fixtures, or dealing with test isolation issues.
npx claudepluginhub versoxbt/claude-initial-setup --plugin claude-initial-setupThis skill uses the workspace's default tool permissions.
Well-structured tests are maintainable, fast, and reliable. This skill covers how to organize test files, create reusable fixtures and factories, ensure test isolation, and configure test environments.
Generates design tokens/docs from CSS/Tailwind/styled-components codebases, audits visual consistency across 10 dimensions, detects AI slop in UI.
Records polished WebM UI demo videos of web apps using Playwright with cursor overlay, natural pacing, and three-phase scripting. Activates for demo, walkthrough, screen recording, or tutorial requests.
Delivers idiomatic Kotlin patterns for null safety, immutability, sealed classes, coroutines, Flows, extensions, DSL builders, and Gradle DSL. Use when writing, reviewing, refactoring, or designing Kotlin code.
Well-structured tests are maintainable, fast, and reliable. This skill covers how to organize test files, create reusable fixtures and factories, ensure test isolation, and configure test environments.
Co-locate tests with source files for discoverability:
src/
services/
auth.ts
auth.test.ts # Unit tests next to source
billing.ts
billing.test.ts
routes/
users.ts
users.test.ts
test/
integration/
api.test.ts # Integration tests in separate dir
e2e/
login.spec.ts # E2E tests in dedicated dir
fixtures/
users.json # Shared test data
factories/
user.factory.ts # Data factories
helpers/
setup.ts # Test setup utilities
db.ts # Database helpers
Fixtures are pre-defined data objects for predictable testing:
// test/fixtures/users.ts
export const validUser = {
email: 'test@example.com',
name: 'Test User',
role: 'member',
} as const
export const adminUser = {
email: 'admin@example.com',
name: 'Admin User',
role: 'admin',
} as const
export const invalidUser = {
email: 'not-an-email',
name: '',
role: 'unknown',
} as const
Usage in tests:
import { validUser, adminUser } from '../fixtures/users'
it('creates a user', async () => {
const result = await createUser(validUser)
expect(result.email).toBe(validUser.email)
})
Factories generate unique test data with sensible defaults. Override only what matters for each test:
TypeScript (with custom factory):
// test/factories/user.factory.ts
let counter = 0
interface UserOverrides {
email?: string
name?: string
role?: string
}
export function buildUser(overrides: UserOverrides = {}) {
counter += 1
return {
email: `user-${counter}@test.com`,
name: `User ${counter}`,
role: 'member',
...overrides,
}
}
// Usage
it('creates admin user', () => {
const user = buildUser({ role: 'admin' })
// user.email is unique, user.role is 'admin'
})
Python (with factory_boy and Faker):
# test/factories.py
import factory
from faker import Faker
from myapp.models import User
fake = Faker()
class UserFactory(factory.Factory):
class Meta:
model = User
email = factory.LazyAttribute(lambda _: fake.email())
name = factory.LazyAttribute(lambda _: fake.name())
role = "member"
# Usage
def test_create_admin():
user = UserFactory(role="admin")
assert user.role == "admin"
assert "@" in user.email # Unique, realistic email
Each test must run independently. No test should depend on another's side effects:
// test/helpers/setup.ts
import { beforeEach, afterEach, afterAll } from 'vitest'
import { db } from '../../src/db'
beforeEach(async () => {
await db.migrate.latest() // Ensure schema is current
})
afterEach(async () => {
await db.raw('TRUNCATE TABLE users CASCADE')
await db.raw('TRUNCATE TABLE posts CASCADE')
})
afterAll(async () => {
await db.destroy() // Close connection pool
})
Three approaches, pick one per project:
| Strategy | How | Best For |
|---|---|---|
| Truncate (recommended) | TRUNCATE TABLE x CASCADE in afterEach | Most projects |
| Transaction rollback | Begin txn in beforeEach, rollback in afterEach | Fast cleanup, no cascade issues |
| Dedicated test DB | Django @pytest.fixture(autouse=True) with db fixture | Django/framework-managed |
Vitest:
// vitest.config.ts
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
globals: true,
environment: 'node',
setupFiles: ['./test/helpers/setup.ts'],
coverage: {
provider: 'v8',
reporter: ['text', 'html'],
thresholds: { lines: 80, branches: 80, functions: 80 },
},
include: ['src/**/*.test.ts'],
exclude: ['node_modules', 'dist'],
},
})
pytest:
# pyproject.toml
[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py"]
addopts = "--strict-markers --tb=short -q"
[tool.coverage.run]
source = ["src"]
omit = ["tests/*"]
[tool.coverage.report]
fail_under = 80
afterAll(() => db.destroy()) causes connection pool exhaustion and hanging test processes.test/ directory should never be imported by src/. Keep test utilities isolated.| Concept | Purpose | Location |
|---|---|---|
| Fixtures | Static, predictable test data | test/fixtures/ |
| Factories | Dynamic, unique test data | test/factories/ |
| Helpers | Reusable test utilities | test/helpers/ |
| Setup | beforeEach/afterEach/afterAll | test/helpers/setup.ts |
| Config | Test runner configuration | vitest.config.ts / jest.config.ts |
Isolation: Each test sets up and tears down its own state. Cleanup: Truncate tables or rollback transactions after each test. Connections: Always close DB pools in afterAll. Coverage: Configure 80% threshold in test runner config.