From sdd-mcp
Generates unit, integration, and edge case tests following TDD for code files or functions. Adapts to existing test frameworks like Jest. Invoke via /sdd-test-gen [path|function].
npx claudepluginhub yi-john-huang/sdd-mcpThis skill uses the workspace's default tool permissions.
Generate comprehensive tests following Test-Driven Development (TDD) methodology. Write tests that serve as living documentation and ensure code correctness.
Generates unit, integration, and e2e tests for code using Jest, Vitest, Pytest, Cypress, or Playwright. Applies strategies like standard, scenario, property, mutation with edge case coverage.
Generates test files from acceptance criteria, tasks, or source code. Auto-detects test framework, follows project conventions, and spawns parallel test-writer agents.
Share bugs, ideas, or general feedback.
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: 'test@example.com', 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: 'test@example.com' });
// Act & Assert
await expect(userService.createUser({ email: 'test@example.com' }))
.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: 'test@example.com', name: 'Test' });
expect(response.status).toBe(201);
// Verify email was queued
expect(await getEmailQueue()).toContainEqual(
expect.objectContaining({ to: 'test@example.com' })
);
});
});
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 () => { ... });
});
});