Analyze existing code and generate comprehensive unit tests to improve test coverage. This skill is for **retrofitting tests onto existing codebases**, not TDD (where tests are written first).
/plugin marketplace add marcel-Ngan/ai-dev-team/plugin install marcel-ngan-ai-dev-team@marcel-Ngan/ai-dev-teamThis skill inherits all available tools. When active, it can use any tool Claude has access to.
Analyze existing code and generate comprehensive unit tests to improve test coverage. This skill is for retrofitting tests onto existing codebases, not TDD (where tests are written first).
| Scenario | Skill to Use | Tests Written |
|---|---|---|
| TDD (new code) | skills/testing/unit | BEFORE implementation |
| Retrofit (existing code) | skills/testing/add-unit-tests | AFTER code exists |
Before generating tests, analyze the target code:
## Code Analysis Checklist
### Structure
- [ ] Identify public methods/functions (test surface)
- [ ] Identify private methods (test through public API)
- [ ] Map dependencies (what needs mocking)
- [ ] Note inheritance/composition patterns
### Behavior
- [ ] Identify input parameters and types
- [ ] Identify return values and types
- [ ] Map conditional branches (if/else, switch)
- [ ] Identify loops and iteration patterns
- [ ] Note error handling paths (try/catch, throws)
### Edge Cases
- [ ] Null/undefined inputs
- [ ] Empty collections/strings
- [ ] Boundary values (0, -1, MAX_INT)
- [ ] Invalid type inputs
- [ ] Concurrent access patterns
## Dependency Analysis
| Dependency | Type | Mock Strategy |
|------------|------|---------------|
| {{dep1}} | External service | Full mock |
| {{dep2}} | Database | Test database or mock |
| {{dep3}} | Internal module | Spy or partial mock |
| {{dep4}} | Static/global | Module mock |
## Test Cases for {{targetFunction/Class}}
### Happy Path
1. {{normalCase1}} → expects {{result1}}
2. {{normalCase2}} → expects {{result2}}
### Edge Cases
1. {{edgeCase1}} → expects {{result1}}
2. {{edgeCase2}} → expects {{result2}}
### Error Cases
1. {{errorCase1}} → expects {{error1}}
2. {{errorCase2}} → expects {{error2}}
### Boundary Cases
1. {{boundaryCase1}} → expects {{result1}}
2. {{boundaryCase2}} → expects {{result2}}
/**
* Unit tests for {{functionName}}
* Generated for existing code - retrofit coverage
*
* Source: {{sourceFile}}:{{lineNumber}}
*/
describe('{{functionName}}', () => {
// Dependencies
let mockDep1: jest.Mocked<Dep1Type>;
let mockDep2: jest.Mocked<Dep2Type>;
beforeEach(() => {
// Fresh mocks for each test
mockDep1 = {
method1: jest.fn(),
method2: jest.fn(),
};
mockDep2 = {
method1: jest.fn(),
};
});
afterEach(() => {
jest.clearAllMocks();
});
describe('happy path', () => {
it('should {{expectedBehavior}} when {{condition}}', () => {
// Arrange
const input = {{validInput}};
mockDep1.method1.mockReturnValue({{mockReturn}});
// Act
const result = {{functionName}}(input, mockDep1);
// Assert
expect(result).toEqual({{expectedOutput}});
expect(mockDep1.method1).toHaveBeenCalledWith({{expectedArgs}});
});
it('should {{expectedBehavior2}} when {{condition2}}', () => {
// Arrange
const input = {{validInput2}};
// Act
const result = {{functionName}}(input);
// Assert
expect(result).toEqual({{expectedOutput2}});
});
});
describe('edge cases', () => {
it('should handle null input', () => {
// Arrange
const input = null;
// Act & Assert
expect(() => {{functionName}}(input)).toThrow({{ExpectedError}});
// OR
expect({{functionName}}(input)).toBeNull();
});
it('should handle empty {{collection/string}}', () => {
// Arrange
const input = {{emptyValue}};
// Act
const result = {{functionName}}(input);
// Assert
expect(result).toEqual({{expectedForEmpty}});
});
it.each([
[{{boundaryInput1}}, {{expected1}}],
[{{boundaryInput2}}, {{expected2}}],
[{{boundaryInput3}}, {{expected3}}],
])('should return %s for boundary input %s', (input, expected) => {
expect({{functionName}}(input)).toBe(expected);
});
});
describe('error handling', () => {
it('should throw {{ErrorType}} when {{errorCondition}}', () => {
// Arrange
const invalidInput = {{invalidInput}};
// Act & Assert
expect(() => {{functionName}}(invalidInput))
.toThrow({{ErrorType}});
});
it('should propagate errors from {{dependency}}', () => {
// Arrange
mockDep1.method1.mockImplementation(() => {
throw new Error('Dependency failure');
});
// Act & Assert
expect(() => {{functionName}}(validInput, mockDep1))
.toThrow('Dependency failure');
});
});
});
/**
* Unit tests for {{ClassName}}
* Generated for existing code - retrofit coverage
*
* Source: {{sourceFile}}
*/
describe('{{ClassName}}', () => {
let instance: {{ClassName}};
let mockDep1: jest.Mocked<Dep1>;
let mockDep2: jest.Mocked<Dep2>;
beforeEach(() => {
mockDep1 = createMockDep1();
mockDep2 = createMockDep2();
instance = new {{ClassName}}(mockDep1, mockDep2);
});
afterEach(() => {
jest.clearAllMocks();
});
describe('constructor', () => {
it('should initialize with provided dependencies', () => {
expect(instance).toBeDefined();
// Verify initial state if accessible
});
it('should throw if required dependency is missing', () => {
expect(() => new {{ClassName}}(null, mockDep2))
.toThrow('{{expectedError}}');
});
});
describe('{{methodName}}', () => {
describe('when {{normalCondition}}', () => {
it('should {{expectedBehavior}}', async () => {
// Arrange
const input = {{testInput}};
mockDep1.someMethod.mockResolvedValue({{mockValue}});
// Act
const result = await instance.{{methodName}}(input);
// Assert
expect(result).toEqual({{expected}});
expect(mockDep1.someMethod).toHaveBeenCalledTimes(1);
});
});
describe('when {{errorCondition}}', () => {
it('should {{errorBehavior}}', async () => {
// Arrange
mockDep1.someMethod.mockRejectedValue(new Error('Failed'));
// Act & Assert
await expect(instance.{{methodName}}(input))
.rejects.toThrow('Failed');
});
});
});
// Repeat for each public method...
});
describe('{{asyncFunctionName}}', () => {
describe('successful operations', () => {
it('should resolve with {{expected}} when {{condition}}', async () => {
// Arrange
const input = {{input}};
mockService.fetch.mockResolvedValue({{mockData}});
// Act
const result = await {{asyncFunctionName}}(input);
// Assert
expect(result).toEqual({{expected}});
});
it('should handle concurrent calls', async () => {
// Arrange
const inputs = [{{input1}}, {{input2}}, {{input3}}];
// Act
const results = await Promise.all(
inputs.map(input => {{asyncFunctionName}}(input))
);
// Assert
expect(results).toHaveLength(3);
});
});
describe('failure scenarios', () => {
it('should reject with {{ErrorType}} when {{errorCondition}}', async () => {
// Arrange
mockService.fetch.mockRejectedValue(new Error('Network error'));
// Act & Assert
await expect({{asyncFunctionName}}({{input}}))
.rejects.toThrow('Network error');
});
it('should handle timeout', async () => {
// Arrange
jest.useFakeTimers();
mockService.fetch.mockImplementation(
() => new Promise(resolve => setTimeout(resolve, 10000))
);
// Act
const promise = {{asyncFunctionName}}(input);
jest.advanceTimersByTime(5000);
// Assert
await expect(promise).rejects.toThrow('Timeout');
jest.useRealTimers();
});
});
});
# Run coverage on target file to identify gaps
npx jest --coverage --collectCoverageFrom='{{targetFile}}' --coverageReporters=text
# Output shows:
# - Lines not covered
# - Branches not covered
# - Functions not covered
| Metric | Minimum | Recommended |
|---|---|---|
| Line | 80% | 90%+ |
| Branch | 70% | 85%+ |
| Function | 90% | 100% |
## High Priority (Must Cover)
- [ ] Public API methods
- [ ] Business logic functions
- [ ] Data validation
- [ ] Error handling paths
- [ ] Security-sensitive code
## Medium Priority (Should Cover)
- [ ] Helper functions
- [ ] Data transformations
- [ ] Edge cases
## Lower Priority (Nice to Have)
- [ ] Simple getters/setters
- [ ] Logging statements
- [ ] Debug-only code
When generating tests, provide:
## Generated Unit Tests for {{target}}
### Analysis Summary
- **Target:** {{file/function/class}}
- **Current Coverage:** {{percentage}}%
- **Test Cases Generated:** {{count}}
- **Expected Coverage After:** {{percentage}}%
### Files Created/Modified
- `{{testFilePath}}`
### Test Summary
| Category | Count |
|----------|-------|
| Happy path | {{n}} |
| Edge cases | {{n}} |
| Error cases | {{n}} |
| Boundary | {{n}} |
### Run Tests
\`\`\`bash
npx jest {{testFilePath}} --coverage
\`\`\`
| Agent | Usage |
|---|---|
| Senior Developer | Primary: Generates unit tests for existing code, reviews generated tests |
| Junior Developer | May request tests for code they're working on |
| QA Engineer | Reviews unit test coverage, identifies gaps |
| Anti-Pattern | Problem | Better Approach |
|---|---|---|
| Testing private methods | Brittle, implementation-coupled | Test through public API |
| 100% coverage obsession | Diminishing returns | Focus on critical paths |
| Duplicate test logic | Hard to maintain | Extract test helpers |
| Testing framework code | Waste of time | Trust the framework |
| No assertions | False confidence | Always assert something |
| Over-mocking | Tests don't reflect reality | Mock only boundaries |
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.