Unit Test Improver

Reviews existing unit tests for gaps, weak assertions, and missing edge cases, then rewrites them to be more robust.

8 stars

Best use case

Unit Test Improver is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Reviews existing unit tests for gaps, weak assertions, and missing edge cases, then rewrites them to be more robust.

Teams using Unit Test Improver should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/unit-test-improver/SKILL.md --create-dirs "https://raw.githubusercontent.com/Notysoty/openagentskills/main/skills/unit-test-improver/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/unit-test-improver/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How Unit Test Improver Compares

Feature / AgentUnit Test ImproverStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Reviews existing unit tests for gaps, weak assertions, and missing edge cases, then rewrites them to be more robust.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Unit Test Improver

## What this skill does

This 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.

Use 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.

## How to use

### Claude Code / Cline

Copy this file to `.agents/skills/unit-test-improver/SKILL.md` in your project root.

Then ask:
- *"Use the Unit Test Improver skill on `tests/cart.test.ts`."*
- *"Review and improve the unit tests for `calculateDiscount` using the Unit Test Improver skill."*

Provide both the test file and the code being tested.

### Cursor

Add 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.

### Codex

Paste both the test file (labeled "TESTS") and the source file (labeled "SOURCE") and ask Codex to follow the instructions below.

## The Prompt / Instructions for the Agent

When asked to improve unit tests, follow these steps:

### Step 1 — Read both the tests and the source

Read 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.

### Step 2 — Identify test quality issues

Check every test for these problems:

**Weak assertions**
- `expect(result).toBeTruthy()` instead of `expect(result).toBe(true)` — passes for any truthy value
- `expect(result).toBeDefined()` when the actual value should be checked
- `expect(fn).not.toThrow()` without checking the return value
- Asserting on the wrong field (e.g., checking `result.id` but not `result.value`)

**Missing coverage**
- The happy path is tested but no error paths
- No tests for null/undefined inputs
- No tests for boundary values (empty array, zero, max value)
- No tests for the cases identified in the source code's conditional branches

**Tests that test implementation, not behavior**
- Asserting that a specific internal function was called, when what matters is the output
- Asserting on exact internal state that's an implementation detail
- Tests that will break if you rename a private variable

**Poor test structure**
- Tests with no clear Arrange/Act/Assert structure
- Multiple unrelated assertions in a single test (makes failures hard to diagnose)
- Test names that don't describe the expected behavior (e.g., `it('works')`)
- Setup code duplicated across many tests instead of using `beforeEach`

**Over-mocking**
- Mocking the thing being tested, not just its dependencies
- Mocking a dependency and then asserting on the mock instead of the real output
- Tests that pass even if you delete the source code (because everything is mocked)

### Step 3 — Identify missing test cases

Using 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.

### Step 4 — Rewrite the tests

Rewrite the full test file applying these principles:

1. **Test names should be sentences**: `it('returns 0 when the cart is empty')` not `it('cart test')`
2. **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
3. **Use `describe` blocks** to group tests by function or scenario
4. **Assert on the output, not the internals** — if the code produces the right result, the implementation is correct
5. **Test all branches** — every `if`, `else`, `catch`, and `switch` case should have a test
6. **Use concrete expected values** — `expect(total).toBe(29.99)` not `expect(total).toBeGreaterThan(0)`
7. **Arrange/Act/Assert** structure in every test:
   ```ts
   // Arrange
   const cart = [{ price: 10, qty: 3 }];
   // Act
   const total = calculateTotal(cart);
   // Assert
   expect(total).toBe(30);
   ```

### Step 5 — Format the output

First, provide a review summary:

```markdown
## Test Review Summary

### Issues found
- [List each issue with the test name or line number]

### Missing coverage
- [List each missing case]
```

Then provide the complete rewritten test file.

## Example

**Input to Agent:**
> "Use the Unit Test Improver skill.
>
> SOURCE (`discount.ts`):
> ```ts
> export function calculateDiscount(price: number, code: string): number {
>   if (code === 'SAVE10') return price * 0.9;
>   if (code === 'SAVE25') return price * 0.75;
>   if (price > 100) return price * 0.95;
>   return price;
> }
> ```
>
> TESTS (`discount.test.ts`):
> ```ts
> it('applies discount', () => {
>   expect(calculateDiscount(50, 'SAVE10')).toBeTruthy();
> });
> it('works', () => {
>   const result = calculateDiscount(200, '');
>   expect(result).toBeDefined();
> });
> ```"

**Output from Agent:**

> ## Test Review Summary
>
> ### Issues found
> - `'applies discount'`: Uses `toBeTruthy()` — passes for any non-zero number, wouldn't catch a bug returning the wrong discount amount
> - `'works'`: Uses `toBeDefined()` — passes as long as the function doesn't throw; doesn't verify the correct value
> - Both test names are vague and don't describe expected behavior
>
> ### Missing coverage
> - `SAVE25` code not tested
> - Price > 100 with no code not tested
> - Invalid/unknown coupon code with price ≤ 100 not tested
> - Zero price not tested
> - Negative price not tested
>
> ---
>
> ```ts
> import { calculateDiscount } from './discount';
>
> describe('calculateDiscount', () => {
>   describe('with coupon codes', () => {
>     it('applies 10% discount for SAVE10 code', () => {
>       expect(calculateDiscount(100, 'SAVE10')).toBe(90);
>     });
>
>     it('applies 25% discount for SAVE25 code', () => {
>       expect(calculateDiscount(100, 'SAVE25')).toBe(75);
>     });
>
>     it('coupon codes take priority over price-based discount', () => {
>       expect(calculateDiscount(200, 'SAVE10')).toBe(180);
>     });
>   });
>
>   describe('without coupon codes', () => {
>     it('applies 5% discount when price is above 100', () => {
>       expect(calculateDiscount(200, '')).toBe(190);
>     });
>
>     it('applies no discount when price is exactly 100', () => {
>       expect(calculateDiscount(100, '')).toBe(100);
>     });
>
>     it('applies no discount when price is below 100', () => {
>       expect(calculateDiscount(50, '')).toBe(50);
>     });
>   });
>
>   describe('edge cases', () => {
>     it('returns 0 for a zero price', () => {
>       expect(calculateDiscount(0, '')).toBe(0);
>     });
>
>     it('unknown coupon code falls through to price-based logic', () => {
>       expect(calculateDiscount(200, 'INVALID')).toBe(190);
>     });
>   });
> });
> ```

## Notes

- Always read the source code — tests cannot be properly evaluated without understanding what the code is supposed to do.
- If the source code itself has bugs, note them separately. Don't write tests that encode the buggy behavior.
- This skill rewrites tests, not source code. If improving the tests reveals a bug, flag it but don't fix it automatically.

Related Skills

Unit Test Writer

8
from Notysoty/openagentskills

Generates comprehensive unit tests for any function or module with edge cases.

Playwright Test Builder

8
from Notysoty/openagentskills

Generates robust Playwright end-to-end tests for web pages and user flows.

Landing Page Copy Improver

8
from Notysoty/openagentskills

Rewrites landing page copy to be more compelling, benefit-focused, and conversion-optimized.

Flaky Test Analyzer

8
from Notysoty/openagentskills

Diagnoses why tests pass inconsistently and suggests fixes for timing, ordering, and state isolation issues.

Troubleshooting Guide Builder

8
from Notysoty/openagentskills

Builds a structured troubleshooting guide with symptom → cause → fix format for any tool or system.

Tech Debt Auditor

8
from Notysoty/openagentskills

Identifies and prioritizes technical debt in a codebase with an effort/impact matrix.

Technical Blog Post Writer

8
from Notysoty/openagentskills

Writes engaging, accurate technical blog posts targeted at developer audiences.

Stack Trace Analyzer

8
from Notysoty/openagentskills

Interprets error stack traces to pinpoint root cause, explain what went wrong, and suggest fixes.

SQL Query Optimizer

8
from Notysoty/openagentskills

Reviews SQL queries for performance issues and rewrites them with optimized execution plans.

Sprint Summary Generator

8
from Notysoty/openagentskills

Converts a list of completed tickets or commits into a clear sprint summary for stakeholders.

Social Post Thread Writer

8
from Notysoty/openagentskills

Converts a blog post, idea, or document into an engaging Twitter/X or LinkedIn thread with hooks and CTAs.

SEO Metadata Generator

8
from Notysoty/openagentskills

Generates optimized title tags, meta descriptions, Open Graph tags, and structured data for any web page.