{"id":"d361150b-b3a9-4b95-ad4c-f10bd4752fc3","shortId":"z2vBLq","kind":"skill","title":"Unit Test Improver","tagline":"Reviews existing unit tests for gaps, weak assertions, and missing edge cases, then rewrites them to be more robust.","description":"# Unit Test Improver\n\n## What this skill does\n\nThis skill directs the agent to review an existing set of unit tests and improve them. It looks for weak or incomplete tests — tests that pass even when the code is broken, tests that don't assert the right things, tests that are missing critical edge cases, and tests that test implementation details instead of behavior. The output is an improved, rewritten test suite that is harder to fool and more useful as a safety net.\n\nUse this before a major refactor (so you can trust the tests will catch regressions), during a code review, or when a bug slips past your existing tests.\n\n## How to use\n\n### Claude Code / Cline\n\nCopy this file to `.agents/skills/unit-test-improver/SKILL.md` in your project root.\n\nThen ask:\n- *\"Use the Unit Test Improver skill on `tests/cart.test.ts`.\"*\n- *\"Review and improve the unit tests for `calculateDiscount` using the Unit Test Improver skill.\"*\n\nProvide both the test file and the code being tested.\n\n### Cursor\n\nAdd the instructions below to your `.cursorrules` or paste them into the Cursor AI pane. Then share the test file and the source file side by side.\n\n### Codex\n\nPaste both the test file (labeled \"TESTS\") and the source file (labeled \"SOURCE\") and ask Codex to follow the instructions below.\n\n## The Prompt / Instructions for the Agent\n\nWhen asked to improve unit tests, follow these steps:\n\n### Step 1 — Read both the tests and the source\n\nRead the full test file. Then read the source code being tested. Understand what the function is supposed to do before evaluating whether the tests cover it.\n\n### Step 2 — Identify test quality issues\n\nCheck every test for these problems:\n\n**Weak assertions**\n- `expect(result).toBeTruthy()` instead of `expect(result).toBe(true)` — passes for any truthy value\n- `expect(result).toBeDefined()` when the actual value should be checked\n- `expect(fn).not.toThrow()` without checking the return value\n- Asserting on the wrong field (e.g., checking `result.id` but not `result.value`)\n\n**Missing coverage**\n- The happy path is tested but no error paths\n- No tests for null/undefined inputs\n- No tests for boundary values (empty array, zero, max value)\n- No tests for the cases identified in the source code's conditional branches\n\n**Tests that test implementation, not behavior**\n- Asserting that a specific internal function was called, when what matters is the output\n- Asserting on exact internal state that's an implementation detail\n- Tests that will break if you rename a private variable\n\n**Poor test structure**\n- Tests with no clear Arrange/Act/Assert structure\n- Multiple unrelated assertions in a single test (makes failures hard to diagnose)\n- Test names that don't describe the expected behavior (e.g., `it('works')`)\n- Setup code duplicated across many tests instead of using `beforeEach`\n\n**Over-mocking**\n- Mocking the thing being tested, not just its dependencies\n- Mocking a dependency and then asserting on the mock instead of the real output\n- Tests that pass even if you delete the source code (because everything is mocked)\n\n### Step 3 — Identify missing test cases\n\nUsing the source code, enumerate every branch, condition, and edge case that should be tested. Cross-reference with the existing tests and list what's missing.\n\n### Step 4 — Rewrite the tests\n\nRewrite the full test file applying these principles:\n\n1. **Test names should be sentences**: `it('returns 0 when the cart is empty')` not `it('cart test')`\n2. **One assertion per concept** — multiple `.toBe()` calls are fine if they're testing the same return value; a single test should not mix unrelated concerns\n3. **Use `describe` blocks** to group tests by function or scenario\n4. **Assert on the output, not the internals** — if the code produces the right result, the implementation is correct\n5. **Test all branches** — every `if`, `else`, `catch`, and `switch` case should have a test\n6. **Use concrete expected values** — `expect(total).toBe(29.99)` not `expect(total).toBeGreaterThan(0)`\n7. **Arrange/Act/Assert** structure in every test:\n   ```ts\n   // Arrange\n   const cart = [{ price: 10, qty: 3 }];\n   // Act\n   const total = calculateTotal(cart);\n   // Assert\n   expect(total).toBe(30);\n   ```\n\n### Step 5 — Format the output\n\nFirst, provide a review summary:\n\n```markdown\n## Test Review Summary\n\n### Issues found\n- [List each issue with the test name or line number]\n\n### Missing coverage\n- [List each missing case]\n```\n\nThen provide the complete rewritten test file.\n\n## Example\n\n**Input to Agent:**\n> \"Use the Unit Test Improver skill.\n>\n> SOURCE (`discount.ts`):\n> ```ts\n> export function calculateDiscount(price: number, code: string): number {\n>   if (code === 'SAVE10') return price * 0.9;\n>   if (code === 'SAVE25') return price * 0.75;\n>   if (price > 100) return price * 0.95;\n>   return price;\n> }\n> ```\n>\n> TESTS (`discount.test.ts`):\n> ```ts\n> it('applies discount', () => {\n>   expect(calculateDiscount(50, 'SAVE10')).toBeTruthy();\n> });\n> it('works', () => {\n>   const result = calculateDiscount(200, '');\n>   expect(result).toBeDefined();\n> });\n> ```\"\n\n**Output from Agent:**\n\n> ## Test Review Summary\n>\n> ### Issues found\n> - `'applies discount'`: Uses `toBeTruthy()` — passes for any non-zero number, wouldn't catch a bug returning the wrong discount amount\n> - `'works'`: Uses `toBeDefined()` — passes as long as the function doesn't throw; doesn't verify the correct value\n> - Both test names are vague and don't describe expected behavior\n>\n> ### Missing coverage\n> - `SAVE25` code not tested\n> - Price > 100 with no code not tested\n> - Invalid/unknown coupon code with price ≤ 100 not tested\n> - Zero price not tested\n> - Negative price not tested\n>\n> ---\n>\n> ```ts\n> import { calculateDiscount } from './discount';\n>\n> describe('calculateDiscount', () => {\n>   describe('with coupon codes', () => {\n>     it('applies 10% discount for SAVE10 code', () => {\n>       expect(calculateDiscount(100, 'SAVE10')).toBe(90);\n>     });\n>\n>     it('applies 25% discount for SAVE25 code', () => {\n>       expect(calculateDiscount(100, 'SAVE25')).toBe(75);\n>     });\n>\n>     it('coupon codes take priority over price-based discount', () => {\n>       expect(calculateDiscount(200, 'SAVE10')).toBe(180);\n>     });\n>   });\n>\n>   describe('without coupon codes', () => {\n>     it('applies 5% discount when price is above 100', () => {\n>       expect(calculateDiscount(200, '')).toBe(190);\n>     });\n>\n>     it('applies no discount when price is exactly 100', () => {\n>       expect(calculateDiscount(100, '')).toBe(100);\n>     });\n>\n>     it('applies no discount when price is below 100', () => {\n>       expect(calculateDiscount(50, '')).toBe(50);\n>     });\n>   });\n>\n>   describe('edge cases', () => {\n>     it('returns 0 for a zero price', () => {\n>       expect(calculateDiscount(0, '')).toBe(0);\n>     });\n>\n>     it('unknown coupon code falls through to price-based logic', () => {\n>       expect(calculateDiscount(200, 'INVALID')).toBe(190);\n>     });\n>   });\n> });\n> ```\n\n## Notes\n\n- Always read the source code — tests cannot be properly evaluated without understanding what the code is supposed to do.\n- If the source code itself has bugs, note them separately. Don't write tests that encode the buggy behavior.\n- This skill rewrites tests, not source code. If improving the tests reveals a bug, flag it but don't fix it automatically.","tags":["unit","test","improver","openagentskills","notysoty","agent-skills","claude","claude-code","claude-skills","cline","cursor","llm"],"capabilities":["skill","source-notysoty","skill-unit-test-improver","topic-agent-skills","topic-claude","topic-claude-code","topic-claude-skills","topic-cline","topic-cursor","topic-llm","topic-llm-skills","topic-skills"],"categories":["openagentskills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/Notysoty/openagentskills/unit-test-improver","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add Notysoty/openagentskills","source_repo":"https://github.com/Notysoty/openagentskills","install_from":"skills.sh"}},"qualityScore":"0.454","qualityRationale":"deterministic score 0.45 from registry signals: · indexed on github topic:agent-skills · 8 github stars · SKILL.md body (7,381 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T19:13:25.339Z","embedding":null,"createdAt":"2026-05-18T13:20:47.475Z","updatedAt":"2026-05-18T19:13:25.339Z","lastSeenAt":"2026-05-18T19:13:25.339Z","tsv":"'/discount':867 '0':557,651,967,974,976 '0.75':747 '0.9':741 '0.95':753 '1':249,549 '10':663,876 '100':750,841,852,883,896,928,942,945,947,956 '180':915 '190':933,993 '2':285,567 '200':772,912,931,990 '25':889 '29.99':646 '3':504,593,665 '30':675 '4':537,604 '5':623,677,922 '50':764,959,961 '6':638 '7':652 '75':899 '90':886 'across':456 'act':666 'actual':317 'add':184 'agent':34,238,718,778 'agents/skills/unit-test-improver/skill.md':144 'ai':197 'alway':995 'amount':804 'appli':546,760,784,875,888,921,935,949 'arrang':659 'arrange/act/assert':427,653 'array':363 'ask':150,226,240 'assert':11,66,297,330,386,400,431,480,569,605,671 'automat':1054 'base':908,986 'beforeeach':462 'behavior':85,385,449,833,1032 'block':596 'boundari':360 'branch':379,515,626 'break':413 'broken':61 'bug':128,799,1020,1046 'buggi':1031 'calculatediscount':166,730,763,771,865,869,882,895,911,930,944,958,973,989 'calculatetot':669 'call':393,574 'cannot':1001 'cart':560,565,661,670 'case':15,76,371,508,519,633,707,964 'catch':119,630,797 'check':290,321,326,336 'claud':137 'clear':426 'cline':139 'code':59,123,138,180,266,376,454,498,512,614,733,737,743,837,844,849,873,880,893,902,919,980,999,1009,1017,1039 'codex':211,227 'complet':711 'concept':571 'concern':592 'concret':640 'condit':378,516 'const':660,667,769 'copi':140 'correct':622,821 'coupon':848,872,901,918,979 'cover':282 'coverag':342,703,835 'critic':74 'cross':525 'cross-refer':524 'cursor':183,196 'cursorrul':190 'delet':495 'depend':474,477 'describ':446,595,831,868,870,916,962 'detail':82,409 'diagnos':440 'direct':32 'discount':761,785,803,877,890,909,923,937,951 'discount.test.ts':757 'discount.ts':726 'doesn':814,817 'duplic':455 'e.g':335,450 'edg':14,75,518,963 'els':629 'empti':362,562 'encod':1029 'enumer':513 'error':350 'evalu':278,1004 'even':56,492 'everi':291,514,627,656 'everyth':500 'exact':402,941 'exampl':715 'exist':5,38,132,529 'expect':298,303,312,322,448,641,643,648,672,762,773,832,881,894,910,929,943,957,972,988 'export':728 'failur':437 'fall':981 'field':334 'file':142,177,203,207,216,222,261,545,714 'fine':576 'first':681 'fix':1052 'flag':1047 'fn':323 'follow':229,245 'fool':98 'format':678 'found':691,783 'full':259,543 'function':272,391,601,729,813 'gap':9 'group':598 'happi':344 'hard':438 'harder':96 'identifi':286,372,505 'implement':81,383,408,620 'import':864 'improv':3,25,44,90,155,161,171,242,723,1041 'incomplet':51 'input':356,716 'instead':83,301,459,484 'instruct':186,231,235 'intern':390,403,611 'invalid':991 'invalid/unknown':847 'issu':289,690,694,782 'label':217,223 'line':700 'list':532,692,704 'logic':987 'long':810 'look':47 'major':110 'make':436 'mani':457 'markdown':686 'matter':396 'max':365 'miss':13,73,341,506,535,702,706,834 'mix':590 'mock':465,466,475,483,502 'multipl':429,572 'name':442,551,698,825 'negat':859 'net':105 'non':792 'non-zero':791 'not.tothrow':324 'note':994,1021 'null/undefined':355 'number':701,732,735,794 'one':568 'output':87,399,488,608,680,776 'over-mock':463 'pane':198 'pass':55,307,491,788,808 'past':130,192,212 'path':345,351 'per':570 'poor':420 'price':662,731,740,746,749,752,755,840,851,856,860,907,925,939,953,971,985 'price-bas':906,984 'principl':548 'prioriti':904 'privat':418 'problem':295 'produc':615 'project':147 'prompt':234 'proper':1003 'provid':173,682,709 'qti':664 'qualiti':288 're':579 'read':250,257,263,996 'real':487 'refactor':111 'refer':526 'regress':120 'renam':416 'result':299,304,313,618,770,774 'result.id':337 'result.value':340 'return':328,556,583,739,745,751,754,800,966 'reveal':1044 'review':4,36,124,159,684,688,780 'rewrit':17,538,541,1035 'rewritten':91,712 'right':68,617 'robust':22 'root':148 'safeti':104 'save10':738,765,879,884,913 'save25':744,836,892,897 'scenario':603 'sentenc':554 'separ':1023 'set':39 'setup':453 'share':200 'side':208,210 'singl':434,586 'skill':28,31,156,172,724,1034 'skill-unit-test-improver' 'slip':129 'sourc':206,221,224,256,265,375,497,511,725,998,1016,1038 'source-notysoty' 'specif':389 'state':404 'step':247,248,284,503,536,676 'string':734 'structur':422,428,654 'suit':93 'summari':685,689,781 'suppos':274,1011 'switch':632 'take':903 'test':2,7,24,42,52,53,62,70,78,80,92,117,133,154,164,170,176,182,202,215,218,244,253,260,268,281,287,292,347,353,358,368,380,382,410,421,423,435,441,458,470,489,507,523,530,540,544,550,566,580,587,599,624,637,657,687,697,713,722,756,779,824,839,846,854,858,862,1000,1027,1036,1043 'tests/cart.test.ts':158 'thing':69,468 'throw':816 'tobe':305,573,645,674,885,898,914,932,946,960,975,992 'tobedefin':314,775,807 'tobegreaterthan':650 'tobetruthi':300,766,787 'topic-agent-skills' 'topic-claude' 'topic-claude-code' 'topic-claude-skills' 'topic-cline' 'topic-cursor' 'topic-llm' 'topic-llm-skills' 'topic-skills' 'total':644,649,668,673 'true':306 'trust':115 'truthi':310 'ts':658,727,758,863 'understand':269,1006 'unit':1,6,23,41,153,163,169,243,721 'unknown':978 'unrel':430,591 'use':101,106,136,151,167,461,509,594,639,719,786,806 'vagu':827 'valu':311,318,329,361,366,584,642,822 'variabl':419 'verifi':819 'weak':10,49,296 'whether':279 'without':325,917,1005 'work':452,768,805 'wouldn':795 'write':1026 'wrong':333,802 'zero':364,793,855,970","prices":[{"id":"439073c0-2c27-4fde-ac12-67e775f72bdd","listingId":"d361150b-b3a9-4b95-ad4c-f10bd4752fc3","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"Notysoty","category":"openagentskills","install_from":"skills.sh"},"createdAt":"2026-05-18T13:20:47.475Z"}],"sources":[{"listingId":"d361150b-b3a9-4b95-ad4c-f10bd4752fc3","source":"github","sourceId":"Notysoty/openagentskills/unit-test-improver","sourceUrl":"https://github.com/Notysoty/openagentskills/tree/main/skills/unit-test-improver","isPrimary":false,"firstSeenAt":"2026-05-18T13:20:47.475Z","lastSeenAt":"2026-05-18T19:13:25.339Z"}],"details":{"listingId":"d361150b-b3a9-4b95-ad4c-f10bd4752fc3","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"Notysoty","slug":"unit-test-improver","github":{"repo":"Notysoty/openagentskills","stars":8,"topics":["agent-skills","claude","claude-code","claude-skills","cline","cursor","llm","llm-skills","skills"],"license":"mit","html_url":"https://github.com/Notysoty/openagentskills","pushed_at":"2026-03-28T06:50:19Z","description":"A  community-driven library of reusable AI agent skills for Claude Code, Cursor, Codex, Cline, and more.","skill_md_sha":"ccadd8f17f1d0289071759abe7d3ea62ce486369","skill_md_path":"skills/unit-test-improver/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/Notysoty/openagentskills/tree/main/skills/unit-test-improver"},"layout":"multi","source":"github","category":"openagentskills","frontmatter":{"name":"Unit Test Improver","description":"Reviews existing unit tests for gaps, weak assertions, and missing edge cases, then rewrites them to be more robust."},"skills_sh_url":"https://skills.sh/Notysoty/openagentskills/unit-test-improver"},"updatedAt":"2026-05-18T19:13:25.339Z"}}