Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Test automatically generate comprehensive unit tests from source code covering happy paths, edge cases, and error conditions. Use when creating test coverage for functions, classes, or modules. Trigger with phrases like "generate unit tests", "create tests for", or "add test coverage".
.claude/skills/jeremylongshore-generating-unit-tests/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-05 | ✗→✓ | ▲ Improved | 53% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 60% | 0% |
| case-20 | ✗→✓ | ▲ Improved | 87% | 0% |
| case-21 | ✓→✗ | ▼ Worse | 2% | 0% |
| case-24 | ✓→✗ | ▼ Worse | 107% | 0% |
Automatically generate comprehensive unit tests from source code analysis covering happy paths, edge cases, boundary conditions, and error handling. Supports Jest, Vitest, Mocha (JavaScript/TypeScript), pytest (Python), JUnit 5 (Java), and Go testing with testify.
jest, vitest, pytest, junit-jupiter, or Go testing)__tests__/, tests/, spec/, or *_test.go)jest.mock, unittest.mock, Mockito, or gomock)npm test, pytest, go test)src/utils/parser.ts without __tests__/parser.test.ts).null, undefined, maximum values.*.test.ts, *.spec.js, test_*.py).describe/context blocks by function name.beforeEach/afterEach for setup and teardown.| Error | Cause | Solution | |-------|-------|---------| | Cannot find module on import | Test file path does not match project module resolution | Check tsconfig.json paths and moduleNameMapper in Jest config | | Mock not intercepting calls | Mock defined after module import caches the real implementation | Move jest.mock() calls to the top of the file before any imports | | Async test timeout | Promise never resolves due to missing await or unhandled rejection | Add await before async calls; increase timeout with jest.setTimeout() | | Tests pass alone but fail together | Shared mutable state leaking between tests | Reset state in afterEach; avoid module-level variables; use jest.isolateModules() | | Snapshot mismatch on first run | No existing snapshot baseline | Run with --updateSnapshot on first execution to create the baseline |
Jest test for a string utility:
typescriptimport { slugify } from '../src/utils/slugify'; describe('slugify', () => { it('converts spaces to hyphens', () => { expect(slugify('hello world')).toBe('hello-world'); }); it('lowercases all characters', () => { expect(slugify('Hello World')).toBe('hello-world'); }); it('removes special characters', () => { expect(slugify('hello@world!')).toBe('helloworld'); }); it('handles empty string', () => { expect(slugify('')).toBe(''); }); it('trims leading and trailing whitespace', () => { expect(slugify(' spaced ')).toBe('spaced'); }); });
pytest test for a data validator:
pythonimport pytest from myapp.validators import validate_email class TestValidateEmail: def test_accepts_valid_email(self): assert validate_email("user@example.com") is True def test_rejects_missing_at_sign(self): assert validate_email("userexample.com") is False def test_rejects_empty_string(self): assert validate_email("") is False def test_rejects_none(self): with pytest.raises(TypeError): validate_email(None)
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 26,338 | 24,472 | -7% | 1 | 1 | 0% | 5,707 | 4,810 | -16% | 0 | 0 | — |
case-02 | fail→fail | 4,320 | 3,547 | -18% | 1 | 1 | 0% | 267 | 1,732 | +549% | 0 | 0 | — |
case-03 | fail→fail | 2,118 | 38,968 | +1740% | 1 | 1 | 0% | 351 | 9,514 | +2611% | 0 | 0 | — |
case-04 | pass→pass | 11,778 | 10,497 | -11% | 1 | 1 | 0% | 2,511 | 3,517 | +40% | 0 | 0 | — |
case-05 | fail→pass | 14,764 | 15,496 | +5% | 1 | 1 | 0% | 2,771 | 4,233 | +53% | 0 | 0 | — |
case-06 | pass→pass | 14,954 | 8,974 | -40% | 1 | 1 | 0% | 1,949 | 3,129 | +61% | 0 | 0 | — |
case-07 | fail→pass | 18,593 | 13,641 | -27% | 1 | 1 | 0% | 2,522 | 4,024 | +60% | 0 | 0 | — |
case-08 | pass→pass | 17,346 | 20,156 | +16% | 1 | 1 | 0% | 2,562 | 4,456 | +74% | 0 | 0 | — |
case-09 | pass→pass | 7,964 | 7,746 | -3% | 1 | 1 | 0% | 1,590 | 2,845 | +79% | 0 | 0 | — |
case-10 | pass→pass | 17,157 | 16,205 | -6% | 1 | 1 | 0% | 2,700 | 4,010 | +49% | 0 | 0 | — |
case-11 | pass→pass | 13,393 | 17,463 | +30% | 1 | 1 | 0% | 2,942 | 4,381 | +49% | 0 | 0 | — |
case-12 | pass→pass | 17,571 | 18,283 | +4% | 1 | 1 | 0% | 2,792 | 4,171 | +49% | 0 | 0 | — |
case-13 | pass→pass | 10,116 | 7,214 | -29% | 1 | 1 | 0% | 1,851 | 2,759 | +49% | 0 | 0 | — |
case-14 | pass→pass | 17,129 | 18,923 | +10% | 1 | 1 | 0% | 2,150 | 3,558 | +65% | 0 | 0 | — |
case-15 | pass→pass | 5,333 | 7,535 | +41% | 1 | 1 | 0% | 943 | 2,520 | +167% | 0 | 0 | — |
case-16 | pass→pass | 17,799 | 15,769 | -11% | 1 | 1 | 0% | 3,255 | 4,425 | +36% | 0 | 0 | — |
case-17 | pass→pass | 18,726 | 15,880 | -15% | 1 | 1 | 0% | 2,428 | 3,162 | +30% | 0 | 0 | — |
case-18 | pass→pass | 19,301 | 17,298 | -10% | 1 | 1 | 0% | 2,359 | 3,431 | +45% | 0 | 0 | — |
case-19 | pass→pass | 20,625 | 14,194 | -31% | 1 | 1 | 0% | 3,012 | 4,164 | +38% | 0 | 0 | — |
case-20 | fail→pass | 9,826 | 13,732 | +40% | 1 | 1 | 0% | 1,577 | 2,956 | +87% | 0 | 0 | — |
case-21 | pass→fail | 16,846 | 9,969 | -41% | 1 | 1 | 0% | 2,019 | 2,065 | +2% | 0 | 0 | — |
case-22 | pass→pass | 18,002 | 6,571 | -63% | 1 | 1 | 0% | 2,020 | 1,471 | -27% | 0 | 0 | — |
case-23 | pass→pass | 17,188 | 17,823 | +4% | 1 | 1 | 0% | 2,576 | 5,253 | +104% | 0 | 0 | — |
case-24 | pass→fail | 20,746 | 22,330 | +8% | 1 | 1 | 0% | 2,845 | 5,886 | +107% | 0 | 0 | — |
case-25 | pass→pass | 12,640 | 7,863 | -38% | 1 | 1 | 0% | 1,638 | 2,837 | +73% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 25 cases were attempted, and 24 counted toward the lift figure. The other 1 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of 0 percentage points is the difference between those two pass rates over the 24 comparable cases. 3 cases got worse with the skill loaded, and they are included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.