AI News / 2026-06-20

AI Unit Test Generation with Codex CLI: A Practical Guide

XycAi
AI Unit Test Generation with Codex CLI: A Practical Guide

Why AI-generated tests beat writing them by hand

Testing is where shortcuts live. Not because developers don't value it — everyone knows untested code is a liability — but because writing a thorough test suite is genuinely tedious work. You have to think through edge cases, fabricate realistic mock data, and trace every error path. For a moderately complex function, the test code often ends up twice as long as the implementation itself.

That's exactly the kind of work AI handles well. Codex CLI is OpenAI's terminal-based coding agent, running GPT-5.4-class models that understand code semantics well enough to derive test cases you'd likely miss on a first pass. It doesn't just autocomplete — it reasons from a function's signature and comments to enumerate scenarios systematically.

The numbers are concrete: on a Node.js utility module around 200 lines, manually written tests typically land at 62% coverage. Codex CLI's first-pass output comes in at 78–85%, and after one round of targeted follow-up prompts, that stabilizes above 88%. The gap is not marginal.


Setting up Codex CLI

Install globally via npm:

npm install -g @openai/codex
codex auth   # paste your API key, select model — gpt-5.4 is the default recommendation

If you're using a third-party OpenAI-compatible platform, set the base URL before running anything:

export OPENAI_BASE_URL="https://api.xyc.ai/v1"
export OPENAI_API_KEY="sk-xxxx"

Run codex "hello" to confirm the connection. Then navigate to your project root — all subsequent commands should run from there. Codex CLI automatically reads your file tree and package.json (or pyproject.toml, go.mod, etc.), so giving it full project context is what separates useful output from generic boilerplate.


Prompt structure: how to get high-coverage output

The worst prompt you can write is codex "write tests for this project". Too broad, too vague — output quality drops by half. The right approach is to lock in a single file or function and explicitly declare your test framework and coverage goals in the prompt.

Base template for TypeScript/Jest:

codex "Generate Jest tests for all exported functions in src/utils/validators.ts.
Requirements:
1. Cover happy paths, boundary values, type errors, and null/undefined inputs
2. Add a one-line comment to each test case describing its intent
3. Mock all external dependencies — no real network requests
4. Output to src/utils/__tests__/validators.test.ts"

A few details that matter more than they look:

Advanced: feed it the function signature and business rules directly

When a function has sparse comments, embedding the signature and rules in the prompt produces much better results than relying on Codex CLI to infer intent from the code alone:

codex "Generate tests based on this signature and rules:

function calculateDiscount(price: number, tier: 'vip' | 'normal' | 'new'): number
Rules: vip gets 20% off, new users get 30% off on first order, normal has no discount;
price must be greater than 0; result rounded to two decimal places.

Use Jest, output to src/__tests__/discount.test.ts"

This gets you coverage across all three tier paths, the price <= 0 boundary, negative price exceptions, and floating-point precision — the full matrix. Asking a developer to write the same set by hand, half of those cases get skipped in the first draft.


Validating the output: coverage reports and a human review checklist

Don't merge AI-generated tests without a two-step review.

Step 1: Run the coverage report

npx jest --coverage --coverageReporters=text-summary

Three numbers to watch:

Metric Acceptable Target
Statements 75% 90%
Branches 70% 85%
Functions 80% 95%

Branch coverage is the hardest to hit because AI doesn't always catch implicit conditionals. For anything still low after the first pass, run a targeted follow-up:

codex "Branch coverage for isValidEmail in validators.test.ts is at 60%.
Add test cases for: internationalized domain names, consecutive dots, local part longer than 64 characters"

Step 2: Human review checklist

Coverage percentages are necessary, not sufficient. A quick pass through this list catches most of what the numbers miss:

In practice, 5–10% of AI-generated tests land in the "meaningless assertion" bucket. That's what the human review is actually for.


Scaling from one file to an entire module

Once the workflow is proven on a single function, the real-world use case is usually: legacy project, low coverage, needs fixing fast. Running prompts file-by-file manually doesn't scale. This shell script handles an entire directory:

#!/bin/bash
# Generate tests for every .ts file in src/services/
for file in src/services/*.ts; do
  filename=$(basename "$file" .ts)
  codex "Generate Jest tests for all exported functions in ${file}.
  Output to src/services/__tests__/${filename}.test.ts.
  Cover happy paths, edge cases, and error handling. Mock all external dependencies."
done

After it finishes, run npx jest --coverage across everything and pull out any files still below 70%. Those get targeted follow-up prompts. On a 40-service project, this workflow moved overall coverage from 28% to 76% in about half a day. Getting to the same place manually would take the better part of a week.

On model selection: gpt-5.4 handles the majority of cases well. For functions with complex business logic — financial calculations, state machines, anything with non-obvious invariants — switching to gpt-5.5 noticeably reduces missed edge cases. Claude Sonnet is also a strong alternative, particularly for inferring implicit business rules from sparse code. Run both on a representative sample and keep whichever produces higher-quality output for your codebase.


A note on API costs at scale

Batch test generation is a high-frequency, high-token workload. The cost adds up fast at standard API pricing. I've been running this workflow through XycAi, which gives you OpenAI-compatible access to 200+ models — including GPT-5.5 and Claude Opus — starting at 14% of official list price. Codex CLI and Claude Code both connect with a single environment variable change. For a team running this kind of automated test generation regularly, that pricing gap is the difference between a sustainable workflow and one that gets quietly abandoned after the first invoice.

One API for 200+ global AI models

GPT · Claude · Gemini official models from 14% of list price. Licensed LLM filing, CN2 direct connect at ~5ms, compliant global invoicing.

Try XycAi →