Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Generate high-signal unit tests for existing code, behavior-first case selection, boundary and error paths, mocking discipline, mutation-tested quality, and framework-idiomatic output for Vitest, Jest, and pytest.
.claude/skills/pramoddutta-unit-test-generation/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-05 | ✗→✓ | ▲ Improved | 15% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 23% | 0% |
| case-02 | ✓→✗ | ▼ Worse | 39% | 0% |
| case-04 | ✓→✗ | ▼ Worse | 97% | 0% |
| case-12 | ✓→✓ | = Same ✓ | 126% | 0% |
You are an expert software engineer generating unit tests for existing code. Your tests must catch real future bugs, not inflate coverage numbers. Follow these instructions whenever asked to "write tests for" a function, module, or class.
refuses expired coupons beats test_coupon_2.For each public function, enumerate in this order:
Skip: private helpers (test through the public surface), trivial getters, framework glue.
typescriptimport { describe, it, expect, vi, beforeEach } from 'vitest'; import { calculateDiscount } from './discount'; import * as rates from './rates'; describe('calculateDiscount', () => { it('applies percentage discount to eligible subtotal', () => { expect(calculateDiscount({ subtotal: 200, code: 'SAVE10' })).toEqual({ total: 180, applied: true }); }); it.each([ [0, 0], // zero subtotal [0.01, 0.01], // minimum [49.99, 49.99], // just under threshold: no discount [50, 45], // threshold boundary: discount applies ])('boundary: subtotal %f -> total %f', (subtotal, total) => { expect(calculateDiscount({ subtotal, code: 'SAVE10' }).total).toBeCloseTo(total, 2); }); it('throws CodeExpiredError with the expiry date for expired codes', () => { expect(() => calculateDiscount({ subtotal: 100, code: 'XMAS2024' })) .toThrowError(expect.objectContaining({ name: 'CodeExpiredError' })); }); it('does not mutate the input order object', () => { const input = Object.freeze({ subtotal: 100, code: 'SAVE10' }); expect(() => calculateDiscount(input)).not.toThrow(); }); it('fetches live rates only for FX orders (mock at the boundary)', async () => { const spy = vi.spyOn(rates, 'fetchRate').mockResolvedValue(1.1); await calculateDiscount({ subtotal: 100, code: 'SAVE10', currency: 'EUR' }); expect(spy).toHaveBeenCalledWith('EUR'); // interaction that IS the contract }); });
pythonimport pytest from discount import calculate_discount, CodeExpiredError class TestCalculateDiscount: def test_applies_percentage_to_eligible_subtotal(self): assert calculate_discount(subtotal=200, code="SAVE10").total == 180 @pytest.mark.parametrize("subtotal,total", [ (0, 0), (0.01, 0.01), (49.99, 49.99), (50, 45), ]) def test_threshold_boundaries(self, subtotal, total): assert calculate_discount(subtotal=subtotal, code="SAVE10").total == pytest.approx(total) def test_expired_code_raises_with_expiry(self): with pytest.raises(CodeExpiredError, match=r"expired on \d{4}-\d{2}-\d{2}"): calculate_discount(subtotal=100, code="XMAS2024") def test_unknown_code_is_no_op_not_error(self): result = calculate_discount(subtotal=100, code="NOPE") assert result.total == 100 and result.applied is False
Mock ONLY at architectural boundaries: network, filesystem, clock, randomness, databases, third-party SDKs. Never mock the module under test's own collaborators just to isolate lines.
vi.useFakeTimers() / freezegun; no test should depend on real now()vitest run --coverage or pytest --cov; inspect UNCOVERED branches and either add a behavior case or document why it is unreachable. Do not chase 100%.toHaveBeenCalledTimes on internals so refactors fail without behavior changes| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-12 | pass→pass | 15,461 | 18,607 | +20% | 1 | 1 | 0% | 1,703 | 3,857 | +126% | 0 | 0 | — |
case-19 | pass→pass | 18,146 | 21,341 | +18% | 1 | 1 | 0% | 3,204 | 4,398 | +37% | 0 | 0 | — |
case-11 | pass→pass | 9,003 | 17,027 | +89% | 1 | 1 | 0% | 1,510 | 3,621 | +140% | 0 | 0 | — |
case-01 | pass→pass | 17,839 | 19,654 | +10% | 1 | 1 | 0% | 2,096 | 4,243 | +102% | 0 | 0 | — |
case-02 | pass→fail | 28,961 | 25,893 | -11% | 1 | 1 | 0% | 4,343 | 6,045 | +39% | 0 | 0 | — |
case-03 | pass→pass | 18,093 | 23,355 | +29% | 1 | 1 | 0% | 2,278 | 4,948 | +117% | 0 | 0 | — |
case-04 | pass→fail | 29,969 | 34,446 | +15% | 1 | 1 | 0% | 3,851 | 7,583 | +97% | 0 | 0 | — |
case-05 | fail→pass | 39,711 | 35,747 | -10% | 1 | 1 | 0% | 6,956 | 7,973 | +15% | 0 | 0 | — |
case-06 | fail→pass | 28,792 | 26,268 | -9% | 1 | 1 | 0% | 4,509 | 5,566 | +23% | 0 | 0 | — |
case-07 | pass→pass | 28,369 | 25,888 | -9% | 1 | 1 | 0% | 4,384 | 5,398 | +23% | 0 | 0 | — |
case-08 | pass→pass | 14,664 | 20,882 | +42% | 1 | 1 | 0% | 2,541 | 4,160 | +64% | 0 | 0 | — |
case-09 | pass→pass | 19,720 | 17,722 | -10% | 1 | 1 | 0% | 2,354 | 3,732 | +59% | 0 | 0 | — |
case-10 | pass→pass | 18,886 | 21,607 | +14% | 1 | 1 | 0% | 2,430 | 4,298 | +77% | 0 | 0 | — |
case-13 | pass→pass | 15,661 | 18,124 | +16% | 1 | 1 | 0% | 1,958 | 4,082 | +108% | 0 | 0 | — |
case-14 | pass→pass | 19,046 | 16,576 | -13% | 1 | 1 | 0% | 2,112 | 3,340 | +58% | 0 | 0 | — |
case-15 | pass→pass | 13,168 | 15,836 | +20% | 1 | 1 | 0% | 1,841 | 3,306 | +80% | 0 | 0 | — |
case-16 | fail→fail | 17,275 | 23,180 | +34% | 1 | 1 | 0% | 2,820 | 4,799 | +70% | 0 | 0 | — |
case-17 | pass→pass | 22,578 | 20,857 | -8% | 1 | 1 | 0% | 2,666 | 4,069 | +53% | 0 | 0 | — |
case-18 | pass→pass | 20,778 | 16,268 | -22% | 1 | 1 | 0% | 2,953 | 4,640 | +57% | 0 | 0 | — |
case-20 | pass→pass | 20,865 | 21,987 | +5% | 1 | 1 | 0% | 2,688 | 4,298 | +60% | 0 | 0 | — |
case-21 | pass→pass | 23,794 | 19,525 | -18% | 1 | 1 | 0% | 2,952 | 4,499 | +52% | 0 | 0 | — |
case-22 | pass→pass | 15,668 | 9,152 | -42% | 1 | 1 | 0% | 1,744 | 2,914 | +67% | 0 | 0 | — |
case-23 | pass→pass | 12,776 | 12,738 | -0% | 1 | 1 | 0% | 1,922 | 3,601 | +87% | 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. 23 cases were attempted. The headline lift of 0 percentage points is the difference between those two pass rates over the 23 comparable cases. 2 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.