test-architecture — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited test-architecture (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
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 helpersFixtures are pre-defined data objects for predictable testing:
// test/fixtures/users.ts
export const validUser = {
email: '[email protected]',
name: 'Test User',
role: 'member',
} as const
export const adminUser = {
email: '[email protected]',
name: 'Admin User',
role: 'admin',
} as const
export const invalidUser = {
email: 'not-an-email',
name: '',
role: 'unknown',
} as constUsage 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 emailEach 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 = 80afterAll(() => 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.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.