> For the complete documentation index, see [llms.txt](https://learning.contextqa.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://learning.contextqa.com/testing-with-ai-coding-agents/unit-testing.md).

# Unit Testing with AI Agents

Use Claude Code, Cursor, or Codex to create and verify meaningful unit tests, then connect changed user journeys to ContextQA through MCP.

## Quick answer

Give your coding agent the behavior contract, implementation, existing test conventions, and exact runner command. Ask it to write focused unit tests, run them, and demonstrate that a deliberate defect makes an assertion fail. Keep these tests in your repository. Use ContextQA MCP separately to cover the user-visible workflows affected by the same change; generating a ContextQA case does not execute your Jest, Vitest, pytest, or Node unit suite.

This guide works with [Claude Code](/testing-with-ai-coding-agents/claude-code-testing.md), [Cursor](/testing-with-ai-coding-agents/cursor-testing.md), [Codex](/testing-with-ai-coding-agents/codex-testing.md), and other agents that can inspect a repository and invoke its test runner.

## Decide what belongs in a unit test

A unit test checks a small behavior with controlled dependencies: a price calculation, permission rule, parser, state transition, or retry decision. It should explain a business rule without requiring a deployed application. Prefer an [integration test](/testing-with-ai-coding-agents/integration-testing.md) when the important risk is whether two real components communicate correctly, and an [end-to-end test](/testing-with-ai-coding-agents/end-to-end-testing.md) when the risk spans a user journey.

For a shipping calculation, useful assertions include the exact fee at the free-shipping threshold and rejection of invalid currency values. An assertion that the function returns any number would miss an incorrect fee. The agent needs the expected rule from requirements, not merely an explanation of what the current code happens to do.

## Prerequisites

* A working checkout and a passing baseline, or a recorded list of existing failures.
* The repository's established runner, language version, and package manager.
* Expected behavior, including boundary values and error handling.
* Permission to edit tests and run local commands. Start on a reviewable branch.

The standalone example below uses Node.js 24 or later with no packages. In an existing project, retain its runner instead of adding a second framework. Node provides the `node:test` runner and strict assertion utilities used here. [Node test runner](https://nodejs.org/api/test.html), [assertion reference](https://nodejs.org/api/assert.html).

## 1. Write a small behavior contract

Our illustrative storefront accepts a non-negative integer subtotal in cents. US shipping costs 500 cents below 5,000 cents and is free at or above 5,000. Canadian shipping costs 1,200 cents below 8,000 and is free at or above 8,000. Other countries are unsupported. These are teaching rules, not ContextQA pricing or an ecommerce recommendation.

Create `shipping.mjs`:

```js
export function shippingFee(subtotalCents, country) {
  if (!Number.isSafeInteger(subtotalCents) || subtotalCents < 0) {
    throw new TypeError('subtotalCents must be a non-negative integer');
  }
  const rules = { US: [5000, 500], CA: [8000, 1200] };
  const rule = Object.hasOwn(rules, country) ? rules[country] : null;
  if (!rule) throw new RangeError('unsupported country');
  const [threshold, fee] = rule;
  return subtotalCents >= threshold ? 0 : fee;
}
```

Separating the policy from UI and HTTP code lets the test vary inputs directly. In a real codebase, import the existing production function. Do not have the agent create a duplicate implementation inside the test and then claim the application is covered.

## 2. Ask the agent for cases before code

```
Read the shipping contract, shipping.mjs, and existing test conventions.
Create unit tests using the repository's current runner.

Cover US and CA: zero, one cent below the free-shipping threshold,
exactly at the threshold, and above it. Cover negative, fractional,
NaN, and unsafe integer inputs, plus unsupported country codes.
Use exact expected values from the contract, not values computed by
copying the implementation. Do not change application behavior.

Run the focused tests and report the exact command, exit code, and
assertions that ran. Then demonstrate in a temporary local edit that
changing >= to > causes the threshold test to fail; restore that edit.
Keep failures and skips visible. Do not weaken assertions to get green.
```

A case review catches gaps cheaply. Ask why each test exists and what defect it detects. Avoid generating dozens of variations that all exercise the same branch while missing the threshold or error path.

## 3. Create and run a focused test

Save this smaller starting suite beside the implementation as `shipping.test.mjs`:

```js
import test from 'node:test';
import assert from 'node:assert/strict';
import { shippingFee } from './shipping.mjs';

for (const [country, threshold, fee] of [['US', 5000, 500], ['CA', 8000, 1200]]) {
  test(`${country}: fee changes exactly at the threshold`, () => {
    assert.equal(shippingFee(0, country), fee);
    assert.equal(shippingFee(threshold - 1, country), fee);
    assert.equal(shippingFee(threshold, country), 0);
    assert.equal(shippingFee(threshold + 1, country), 0);
  });
}

test('rejects invalid subtotal values and unsupported countries', () => {
  for (const amount of [-1, 0.5, NaN, Number.MAX_SAFE_INTEGER + 1]) {
    assert.throws(() => shippingFee(amount, 'US'), TypeError);
  }
  assert.throws(() => shippingFee(5000, 'GB'), RangeError);
});
```

Run from that directory:

```bash
node --test shipping.test.mjs
```

This fixture verifies a narrow policy. It does not establish that checkout sends the right subtotal, displays the correct fee, or saves an order. Those require additional layers.

## 4. Review failure quality and coverage

Inspect the actual test output rather than accepting the agent's summary. A syntax error demonstrates that the file could not run; it does not demonstrate that the shipping assertion detects a defect. For the temporary `>=` to `>` mutation, require a failure at the exact-threshold assertion, then restore the implementation and rerun.

When testing asynchronous functions, await their completion so an assertion cannot finish after the test has already ended. Keep clocks, random values, and external calls under explicit control. Mocks are appropriate when isolating a unit, but a passing mocked database call cannot prove the real database accepts a query.

Before opening the PR, check that no `.only`, unintended skips, broad exception swallowing, or changed expected values conceal failures. Coverage helps locate unexecuted branches; it does not establish that assertions are meaningful. Record what remains untested, including unsupported inputs whose behavior has not been specified.

## 5. Connect the change to ContextQA MCP

After the unit suite passes, identify one exposed journey: changing a cart from below to exactly the free-shipping threshold. [Connect ContextQA MCP](/mcp-server/installation-and-setup.md), confirm the intended workspace with a read-only request, and check the tools available in the connected manifest.

The documented `generate_tests_from_code_change` tool accepts `diff_text` and `app_url`. It creates ContextQA cases for affected flows; it is not a wrapper around your native unit runner. Review generated steps and expected amounts before execution. See [test generation](/mcp-server/tool-reference/test-generation.md) and [execution/results](/mcp-server/tool-reference/execution-and-results.md).

```
Using ContextQA MCP, inspect the available tools and intended workspace.
For the shipping-policy diff, prepare a browser test on our approved
staging storefront. Use the approved test account and US destination.

Verify a cart subtotal of $49.99 shows $5.00 shipping. Change it to
$50.00 and verify shipping is $0.00 and the displayed total is correct.
Do not place a real order. Show the created steps and assertions before
execution. Run the reviewed case, retrieve the returned result ID and
step results, and distinguish creation, completion, and assertion pass.
List any unavailable preconditions instead of reporting success.
```

Replace sample amounts if your actual contract differs. The native unit result and ContextQA browser result are separate evidence items associated with the same change.

## Debugging and handoff

If the unit test fails, first compare the contract, input, and observed value. If the unit test passes but the browser fails, inspect serialization, formatting, stale state, and whether checkout uses the same policy. Keep the original failed result when rerunning after a fix.

Your PR handoff should include changed behavior, exact command, test count and failures, the deliberate-defect check, remaining risks, and any ContextQA case/result links actually produced. For portable browser artifacts, use the [export and portability guide](/testing-with-ai-coding-agents/export-and-portability.md). Exporting a browser case does not export or replace this unit suite.

## Common questions

### Can Claude Code, Cursor, or Codex write the whole suite?

They can propose and edit tests when given repository access. The runner's output and reviewed assertions establish what was tested. Generated files alone are not a passing result.

### Should every unit test also become a browser test?

No. Keep detailed input combinations near the unit. Select a few high-risk user journeys to verify the application uses that behavior correctly.

### Can ContextQA MCP execute my local Jest or pytest tests?

This guide does not establish that capability. Run native suites through your agent's approved terminal and existing CI. Use the documented ContextQA tools for ContextQA test cases.

**Next step:** [Set up ContextQA MCP](/mcp-server/installation-and-setup.md) to add a deployed regression check to your code-level tests. For a walkthrough connecting one real PR to release evidence, [book a testing workflow demo](https://contextqa.com/book-a-demo/?utm_source=learning.contextqa.com\&utm_medium=referral\&utm_campaign=docs_demand_gen\&utm_content=unit-testing).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://learning.contextqa.com/testing-with-ai-coding-agents/unit-testing.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
