Install
$ agentstack add skill-xcrrr-claude-skills-test-writer ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Test Writer
Overview
The Test Writer skill produces comprehensive, maintainable tests following established practices: the test pyramid (unit → integration → e2e), the AAA (Arrange-Act-Assert) pattern, meaningful naming conventions, and effective mocking strategies. It helps determine what to test, how to structure test files, what to mock vs. not mock, and how to set coverage targets. Good tests serve as executable documentation that catches regressions before they reach production.
When to Use
- Writing tests for a new function, class, or module
- Adding tests to untested legacy code before refactoring
- Following Test-Driven Development (TDD) — writing tests before implementation
- Evaluating test coverage and identifying what's missing
- Writing integration tests for API endpoints or database interactions
When NOT to Use
- Setting up CI/CD pipelines or test runners (infrastructure concern)
- Load testing or performance benchmarking (different tooling)
- Writing end-to-end browser automation scripts (use a Playwright/Cypress skill)
- Debugging a failing test (use the debugger skill to find the root cause)
Quick Reference
| Level | Scope | Speed | Mock? | Target % | |-------|-------|-------|-------|----------| | Unit | Single function/class | Fast ( { describe('happy path', () => { it('should apply 5% discount for silver tier', () => { // Arrange const price = 100; const tier = 'silver';
// Act const result = calculateDiscount(price, tier);
// Assert expect(result).toBe(5.00); });
it('should apply 10% discount for gold tier', () => { expect(calculateDiscount(100, 'gold')).toBe(10.00); });
it('should apply 20% discount for platinum tier', () => { expect(calculateDiscount(100, 'platinum')).toBe(20.00); });
it('should return 0 discount for unknown tier', () => { expect(calculateDiscount(100, 'bronze')).toBe(0); });
it('should return 0 discount when tier is undefined', () => { expect(calculateDiscount(100, undefined)).toBe(0); });
it('should round to 2 decimal places', () => { // $99.99 * 5% = 4.9995 → rounds to 5.00 expect(calculateDiscount(99.99, 'silver')).toBe(5.00); }); });
describe('error cases', () => { it('should throw when price is zero', () => { expect(() => calculateDiscount(0, 'gold')).toThrow('Price must be positive'); });
it('should throw when price is negative', () => { expect(() => calculateDiscount(-50, 'gold')).toThrow('Price must be positive'); }); });
describe('edge cases', () => { it('should handle very small positive price', () => { expect(calculateDiscount(0.01, 'platinum')).toBe(0.00); });
it('should handle very large price', () => { expect(calculateDiscount(1000000, 'platinum')).toBe(200_000); }); }); });
---
### Example 2: Write an integration test for an API endpoint (Node.js/Jest + Supertest)
**Input:** An Express endpoint to test:
```javascript
// routes/users.js
router.post('/users', async (req, res) => {
const { email, name } = req.body;
if (!email) return res.status(422).json({ error: 'email is required' });
const existing = await db.users.findByEmail(email);
if (existing) return res.status(409).json({ error: 'email already in use' });
const user = await db.users.create({ email, name });
return res.status(201).json(user);
});
Output:
// routes/users.integration.test.js
import request from 'supertest';
import { app } from '../app';
import { db } from '../db';
// Use a real test database — no mocking of db layer
beforeAll(async () => { await db.migrate.latest(); });
afterAll(async () => { await db.destroy(); });
afterEach(async () => { await db.raw('DELETE FROM users'); }); // clean state
describe('POST /users', () => {
describe('successful creation', () => {
it('should create a user and return 201 with user data', async () => {
// Arrange
const payload = { email: 'alice@example.com', name: 'Alice' };
// Act
const res = await request(app).post('/users').send(payload);
// Assert
expect(res.status).toBe(201);
expect(res.body).toMatchObject({
id: expect.any(String),
email: 'alice@example.com',
name: 'Alice',
createdAt: expect.any(String),
});
// Verify persisted to DB
const saved = await db.users.findByEmail('alice@example.com');
expect(saved).not.toBeNull();
});
});
describe('validation errors', () => {
it('should return 422 when email is missing', async () => {
const res = await request(app).post('/users').send({ name: 'Bob' });
expect(res.status).toBe(422);
expect(res.body.error).toBe('email is required');
});
});
describe('conflict errors', () => {
it('should return 409 when email already exists', async () => {
// Arrange — seed an existing user
await db.users.create({ email: 'carol@example.com', name: 'Carol' });
// Act
const res = await request(app)
.post('/users')
.send({ email: 'carol@example.com', name: 'Carol 2' });
// Assert
expect(res.status).toBe(409);
expect(res.body.error).toBe('email already in use');
});
});
});
Best Practices
- Write tests before code (TDD) to drive better API design
- One logical assertion concept per test — multiple
expect()calls are fine if they verify the same behavior - Tests should be deterministic: no random data, no time-dependent behavior (mock
Date.now()) - Keep tests fast — slow tests don't get run; unit tests should complete in milliseconds
- Use test factories or builders for complex object setup to avoid repetition
- Test the contract (what), not the implementation (how) — brittle tests couple to internals
Common Mistakes
- Testing implementation details (private methods, internal state) instead of observable behavior
- Not testing error paths and edge cases — happy-path-only tests miss most bugs
- Over-mocking: mocking so much that tests pass even when real integrations are broken
- Using production database in tests without cleanup — tests pollute each other
- Testing framework code (e.g., testing that Express routing works) instead of your business logic
- Ignoring flaky tests — a flaky test is worse than no test (false confidence)
Tips & Tricks
- Use
test.each(Jest) or@pytest.mark.parametrizefor table-driven tests with multiple input/output pairs - Snapshot tests for complex output structures, but review snapshots on every change
--coverage --collectCoverageFromto see which lines are untested- Use
fakerorfactory-boyto generate realistic test data instead of hand-crafting fixtures - Jest's
jest.useFakeTimers()/ Python'sfreezegunto control time-dependent tests
Related Skills
- [debugger](../debugger/SKILL.md)
- [code-reviewer](../code-reviewer/SKILL.md)
- [api-designer](../api-designer/SKILL.md)
- [refactorer](../refactorer/SKILL.md)
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: xcrrr
- Source: xcrrr/claude-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.