.claude/skills/sdd-test-gen/SKILL.md
Generate comprehensive tests following TDD methodology. Creates unit tests, integration tests, and edge case coverage. Works with existing test frameworks in the project. Invoked via /sdd-test-gen [file-path or function-name].
npx skillsauth add yi-john-huang/sdd-mcp sdd-test-genInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Generate comprehensive tests following Test-Driven Development (TDD) methodology. Write tests that serve as living documentation and ensure code correctness.
"Write a failing test before you write the code to make it pass."
Tests are not an afterthought—they're a design tool that:
┌─────────────────────────────────────┐
│ │
│ ┌─────────┐ Write failing test │
│ │ RED │◄──────────────────────┤
│ └────┬────┘ │
│ │ │
│ ▼ Make it pass │
│ ┌─────────┐ │
│ │ GREEN │ │
│ └────┬────┘ │
│ │ │
│ ▼ Improve code │
│ ┌─────────┐ │
│ │REFACTOR │───────────────────────┘
│ └─────────┘
└─────────────────────────────────────┘
/sdd-test-gen src/services/UserService.ts # Generate tests for file
/sdd-test-gen UserService.createUser # Generate for specific method
/sdd-test-gen src/services/ --integration # Integration tests for module
Before generating tests:
.spec/specs/Generate tests with this structure:
import { UserService } from '../UserService';
import { UserRepository } from '../../repositories/UserRepository';
import { EmailService } from '../../services/EmailService';
// Mock dependencies
jest.mock('../../repositories/UserRepository');
jest.mock('../../services/EmailService');
describe('UserService', () => {
let userService: UserService;
let mockUserRepo: jest.Mocked<UserRepository>;
let mockEmailService: jest.Mocked<EmailService>;
beforeEach(() => {
jest.clearAllMocks();
mockUserRepo = new UserRepository() as jest.Mocked<UserRepository>;
mockEmailService = new EmailService() as jest.Mocked<EmailService>;
userService = new UserService(mockUserRepo, mockEmailService);
});
describe('createUser', () => {
it('should create a user with valid input', async () => {
// Arrange
const input = { email: '[email protected]', name: 'Test User' };
mockUserRepo.save.mockResolvedValue({ id: '1', ...input });
// Act
const result = await userService.createUser(input);
// Assert
expect(result.id).toBeDefined();
expect(mockUserRepo.save).toHaveBeenCalledWith(expect.objectContaining(input));
});
it('should throw error when email already exists', async () => {
// Arrange
mockUserRepo.findByEmail.mockResolvedValue({ id: '1', email: '[email protected]' });
// Act & Assert
await expect(userService.createUser({ email: '[email protected]' }))
.rejects.toThrow('Email already exists');
});
});
});
Test individual functions in isolation:
describe('calculateTotal', () => {
it('should sum all item prices', () => { ... });
it('should apply discount when provided', () => { ... });
it('should handle empty cart', () => { ... });
it('should throw error for negative quantities', () => { ... });
});
Always test:
describe('edge cases', () => {
it('should handle null input gracefully', () => { ... });
it('should handle empty array', () => { ... });
it('should handle maximum allowed length', () => { ... });
it('should reject invalid email format', () => { ... });
});
Verify error paths:
describe('error handling', () => {
it('should throw ValidationError for invalid input', async () => {
await expect(service.create({})).rejects.toThrow(ValidationError);
});
it('should propagate database errors', async () => {
mockRepo.save.mockRejectedValue(new DatabaseError('Connection failed'));
await expect(service.create(validInput)).rejects.toThrow(DatabaseError);
});
});
Test component interactions:
describe('UserService integration', () => {
let app: Express;
let db: Database;
beforeAll(async () => {
db = await createTestDatabase();
app = createApp({ database: db });
});
afterAll(async () => {
await db.close();
});
it('should create user and send welcome email', async () => {
const response = await request(app)
.post('/api/users')
.send({ email: '[email protected]', name: 'Test' });
expect(response.status).toBe(201);
// Verify email was queued
expect(await getEmailQueue()).toContainEqual(
expect.objectContaining({ to: '[email protected]' })
);
});
});
Use the pattern: should [expected behavior] when [condition]
// Good
it('should return empty array when no users match criteria', () => {});
it('should throw AuthError when token is expired', () => {});
it('should create user and return ID when input is valid', () => {});
// Bad
it('test createUser', () => {});
it('works correctly', () => {});
For each generated test:
When generating tests for a spec:
.spec/specs/{feature}/requirements.mdWhen running /sdd-test-gen:
## Test Generation Summary
### Target: {file/function}
### Tests Generated:
- **Unit Tests**: {count}
- **Edge Cases**: {count}
- **Error Handling**: {count}
- **Integration**: {count} (if requested)
### Coverage Targets:
- Statements: 80%+
- Branches: 75%+
- Functions: 90%+
- Lines: 80%+
### Files Created:
- `src/__tests__/unit/{file}.test.ts`
- `src/__tests__/integration/{file}.integration.test.ts` (if requested)
Automatically detect and use project's test framework:
For input: /sdd-test-gen src/services/AuthService.ts
import { AuthService } from '../AuthService';
import { TokenService } from '../../utils/TokenService';
import { UserRepository } from '../../repositories/UserRepository';
jest.mock('../../utils/TokenService');
jest.mock('../../repositories/UserRepository');
describe('AuthService', () => {
// ... setup ...
describe('login', () => {
it('should return token when credentials are valid', async () => { ... });
it('should throw AuthError when user not found', async () => { ... });
it('should throw AuthError when password is incorrect', async () => { ... });
it('should increment failed login count on failure', async () => { ... });
it('should lock account after 5 failed attempts', async () => { ... });
});
describe('logout', () => {
it('should invalidate token when called', async () => { ... });
it('should handle already-logged-out user gracefully', async () => { ... });
});
describe('refreshToken', () => {
it('should return new token when refresh token is valid', async () => { ... });
it('should throw AuthError when refresh token is expired', async () => { ... });
});
});
tools
Implement simple features with best practices. Use when adding small features, bug fixes, or quick enhancements without the full SDD workflow. Invoked via /simple-task <description>.
development
Generate comprehensive tests following TDD methodology. Creates unit tests, integration tests, and edge case coverage. Works with existing test frameworks in the project. Invoked via /sdd-test-gen [file-path or function-name].
testing
Generate TDD task breakdown for SDD workflow. Use when breaking down design into implementable tasks with test-first approach. Invoked via /sdd-tasks <feature-name>.
testing
Create project-specific steering documents for SDD workflow. Use when setting up project context, documenting technology stack, or establishing project conventions. Invoked via /sdd-steering.