The Testing Void: Why AI Assistants Don't Write Tests (and How to Fix It) | Deployxa

AI assistants generate code without tests, which means bugs slip through to production. Here are the 6 reasons and the production checklist to fix them.

← Back to Dispatch Articles
Engineering Log

The Testing Void: Why AI Assistants Don't Write Tests (and How to Fix It)

AI assistants generate code without tests, which means bugs slip through to production. Here are the 6 reasons and the production checklist to fix them.

The Testing Void

You built an app with Cursor, deployed it, and within a week, users reported three bugs: a form that does not submit, a button that does nothing, and a page that crashes on mobile. You had no tests, so you did not catch these bugs before they reached production. What happened? Your app works, but it has bugs, because AI assistants generate code without tests. This is the testing void, and it is one of the most common failures in AI-generated apps. AI assistants focus on functionality, not verification, which means they generate code that works in the happy path but breaks in edge cases. Here are the 6 reasons AI assistants don't write tests, and the production checklist to fix them.

The direct answer is that testing is the practice of verifying that your code works correctly, and it is essential for production reliability. AI assistants generate code without tests, because testing is not the default in most frameworks, and the LLM's training data is dominated by code without tests. The 6 reasons are: no test setup, no test culture, mocks are hard, integration tests are hard, no test maintenance, and no CI/CD integration. Each one has a known cause and a known fix, and applying all 6 fixes gives you a production-ready testing strategy. For more on production reliability, see our article on why AI apps break on the first real user.

Reason 1: No Test Setup

The most common reason AI assistants don't write tests is no test setup. Testing requires a test runner (Jest, Vitest, Pytest), a testing library (React Testing Library, Testing Library), and a configuration file. AI assistants rarely set up these tools, because they are not part of the default boilerplate. The fix is to set up testing tools at the beginning of the project, not as an afterthought. For Next.js, use Vitest and React Testing Library. For Vite, use Vitest (built-in). For Python, use Pytest. For more on setup, see our article on building a self-healing CI/CD pipeline.

Reason 2: No Test Culture

The second reason is no test culture. AI assistants generate code without tests, because the LLM's training data is dominated by code without tests (most tutorials and examples do not include tests). The fix is to explicitly ask the AI assistant to write tests: "Write a function that does X, and write tests for it." The AI assistant will generate both the function and the tests, which is better than generating just the function. For more on prompting AI assistants, see our article on the agentic deployment checklist.

Reason 3: Mocks Are Hard

The third reason is that mocks are hard. Testing code that depends on external services (e.g., a database, an API) requires mocking those services, which is complex. AI assistants often skip tests for code with external dependencies, because the mocking is too complex. The fix is to use mocking libraries (e.g., msw for HTTP mocking, jest.mock for module mocking) and to design your code for testability (e.g., dependency injection, interfaces). For more on mocking, see our article on the state management mess, which covers testable architecture.

Reason 4: Integration Tests Are Hard

The fourth reason is that integration tests are hard. Unit tests (testing individual functions) are easy, but integration tests (testing multiple components together) are complex, because they require a test environment that mimics production. AI assistants rarely write integration tests, because the setup is complex. The fix is to use integration testing tools (e.g., Playwright for end-to-end tests, Testcontainers for database integration tests) and to write a few key integration tests that cover the critical user flows. For more on integration testing, see our article on building a self-healing CI/CD pipeline.

Reason 5: No Test Maintenance

The fifth reason is no test maintenance. Tests need to be maintained as the code changes, but AI assistants rarely update tests when they modify code, which means the tests get out of sync and start failing. The fix is to run tests in CI/CD (so failures are caught immediately) and to update tests whenever you modify code. For more on CI/CD, see our article on building a self-healing CI/CD pipeline.

Reason 6: No CI/CD Integration

The sixth reason is no CI/CD integration. Tests that are not run automatically are tests that are not run at all. AI assistants rarely set up CI/CD to run tests, which means the tests (if they exist) are only run manually. The fix is to set up CI/CD (e.g., GitHub Actions) to run tests on every push and pull request, which catches failures before they reach production. For more on CI/CD, see our article on building a self-healing CI/CD pipeline.

Step-by-Step: The 6-Fix Testing Checklist

Here is the production checklist for fixing the testing void in AI-generated apps.

Fix 1: Set up testing tools

For Next.js (with Vitest and React Testing Library):

npm install -D vitest @testing-library/react @testing-library/jest-dom jsdom

Create vitest.config.ts:

import { defineConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  test: {
    environment: 'jsdom',
    globals: true,
    setupFiles: './vitest.setup.ts',
  },
});

Create vitest.setup.ts:

import '@testing-library/jest-dom';

Add to package.json:

{
  "scripts": {
    "test": "vitest",
    "test:run": "vitest run"
  }
}

Fix 2: Write tests with the AI assistant

When you ask the AI assistant to write a function, also ask it to write tests:

Write a function that validates an email address, and write tests for it
that cover valid emails, invalid emails, and edge cases.

Fix 3: Use mocking libraries

import { rest } from 'msw';
import { setupServer } from 'msw/node';

const server = setupServer(
  rest.get('/api/users', (req, res, ctx) => {
    return res(ctx.json([{ id: 1, name: 'Alice' }]));
  })
);

beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

test('fetches users', async () => {
  const users = await fetchUsers();
  expect(users).toEqual([{ id: 1, name: 'Alice' }]);
});

Fix 4: Write integration tests with Playwright

npm install -D @playwright/test
npx playwright install
// tests/e2e/spec.ts
import { test, expect } from '@playwright/test';

test('user can sign up', async ({ page }) => {
  await page.goto('http://localhost:3000/signup');
  await page.fill('input[name="email"]', '[email protected]');
  await page.fill('input[name="password"]', 'password123');
  await page.click('button[type="submit"]');
  await expect(page).toHaveURL('/dashboard');
});

Fix 5: Run tests in CI/CD

# .github/workflows/test.yml
name: Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm ci
      - run: npm run test:run
      - run: npx playwright test

Fix 6: Maintain tests

When you modify code, update the tests. Run tests before every commit to catch failures early.

Step 7: Verify with deployxa doctor

Run deployxa doctor to verify your app's health. The 14-point readiness engine checks SSL, DNS, environment variables, health endpoints, and container status.

Common Pitfalls and Troubleshooting

The first pitfall is testing implementation details. Tests that test implementation details (e.g., "does the function call this internal method?") break when the implementation changes, even if the behavior is the same. The fix is to test behavior (e.g., "does the function return the correct result?"), not implementation. The second pitfall is not testing edge cases. Tests that only cover the happy path miss bugs that occur in edge cases (e.g., empty input, null values, very large input). The fix is to write tests for edge cases, not just the happy path. The third pitfall is flaky tests. Tests that pass sometimes and fail other times (e.g., due to timing issues, network issues) erode trust in the test suite. The fix is to make tests deterministic (use mocks, avoid real network calls, use deterministic test data). The fourth pitfall is slow tests. Tests that take too long to run (e.g., 10+ minutes) are not run frequently, which means failures are caught late. The fix is to keep tests fast (use unit tests for most of the coverage, reserve integration tests for critical flows). The fifth pitfall is low coverage. Tests that cover only a fraction of the code leave bugs in the untested code. The fix is to measure coverage (e.g., with vitest --coverage) and to aim for at least 80% coverage on critical paths.

Advanced Testing Patterns

Beyond the 6 fixes, testing benefits from several advanced patterns. The first is test-driven development (TDD). TDD is the practice of writing tests before writing the code, which ensures your code is testable and meets the requirements. TDD follows the red-green-refactor cycle: write a failing test (red), write the minimum code to pass the test (green), then refactor the code (refactor). The second is behavior-driven development (BDD). BDD is a variation of TDD that focuses on behavior (e.g., "given a user with no posts, when they visit their profile, then they see a 'no posts' message"), which makes tests more readable and aligned with business requirements. The third is snapshot testing. Snapshot testing captures the output of a component (or function) and compares it to a stored snapshot, which is useful for detecting unexpected changes. Jest and Vitest support snapshot testing out of the box. The fourth is mutation testing. Mutation testing modifies your code (e.g., changes + to -) and checks if your tests catch the mutation, which measures the quality of your tests. Stryker is a popular mutation testing tool for JavaScript. The fifth is contract testing. Contract testing verifies that two services (e.g., a frontend and a backend) agree on their API contract, which is useful for microservices architectures. Pact is a popular contract testing tool. For more on testing, see our articles on building a self-healing CI/CD pipeline and the agentic deployment checklist.

When Testing Is Not a Priority

Testing is not always a priority. For prototypes and MVPs, shipping quickly is more important than testing, and tests can be added later. For hobby projects, tests might not be worth the effort. For apps with a short lifespan (e.g., a marketing page that will be replaced in a month), tests might not be worth the investment. For these apps, focusing on shipping is more important than testing. The key is to match the testing to the app's needs: for production apps with real users, testing is essential; for prototypes and hobby projects, testing can be deferred. For more on testing, see our articles on the dependency hell trap and the performance regression trap.

Conclusion: Tests Are Not Optional

The testing void is not a sign that your AI assistant did a bad job. It is a sign that AI assistants focus on functionality, not verification, and testing requires additional work. By applying the 6-fix production checklist (set up tools, write tests with the AI, use mocks, write integration tests, maintain tests, run in CI/CD), you can build a production-ready testing strategy that catches bugs before they reach production. Stop shipping untested code and start testing.

Ready to ship a tested app? Drag your project to Deployxa Drop for an instant live preview, or install the CLI with npm i -g @deployxa/cli and deploy from your terminal. For more on AI coding patterns, see our articles on the state management mess and the performance regression trap. Learn about the dependency hell trap and the security headers gap in our companion articles. Explore our free developer tools to speed up your workflow.

Ready to deploy with Deployxa?

Deploy your apps globally with automatic SSL and AI diagnostics.

Start Free Now