How to Test Your Code Properly in the Age of AI-Generated Software

The testing pyramid still applies in the AI era — but letting AI write and test its own code is a hidden trap.
Software testing spans three layers — unit, integration, and end-to-end — each catching different types of failures. The testing pyramid recommends maximizing fast, cheap unit tests while limiting expensive end-to-end tests. As AI takes on more coding work, this framework becomes more critical, not less: an AI agent that both implements and tests code can embed the same flawed assumption into both, producing a passing test suite for a broken system. The fix is to anchor correct behavior in external specs, API contracts, or acceptance criteria, and to bring in independent review. AI lowers the cost of feedback loops, but defining what 'correct' means remains a human responsibility.
A program can pass every single unit test and still be broken in production. Maybe the database fee calculation is wrong, maybe two services disagree on an API contract, or maybe every module works fine in isolation but the user's checkout flow simply won't complete. The reason is straightforward: different types of tests catch different types of bugs.
Now that AI is participating in coding at scale, testing hasn't become optional — if anything, it demands a deeper understanding of the underlying logic. Let's walk through the three layers of software testing, explore what each one is actually good at, and examine what changes when AI enters the picture.
Unit Tests: The Foundation of Fast Feedback
Take an online store as an example. Suppose we have a function that calculates the final price of an order, including discounts, taxes, and shipping. A unit test might verify that a 10% discount is applied correctly, or that orders over $50 trigger free shipping.
The key here is that we're testing a small piece of logic in isolation — no database, no external service dependencies. That's precisely why unit tests run extremely fast and can be executed hundreds or thousands of times with every code change. They form the broadest and most numerous layer at the base of the testing hierarchy.
But testing isolated fragments is never enough. In real systems, modules call and depend on each other — and that's exactly the blind spot unit tests can't cover.
Integration Tests: Guarding the System's Boundaries
A checkout service needs to save orders to a database and call a payment service. Unit tests can't reach these cross-module interactions — that's where integration tests come in.
Integration tests verify whether multiple parts of a system can actually work together. For instance, calling the checkout API and confirming it writes the correct data to the database, or checking that the fields the checkout service sends to the payment service match what the payment service expects.

Checkout logic might pass every unit test and still fail here — because a SQL query is malformed, or because two services have fundamentally incompatible understandings of their API contract. These "boundary bugs" are among the most common causes of production incidents, and unit tests will never surface them.
End-to-End Tests: Validating the Complete User Journey
End-to-end tests operate from an entirely different perspective. Instead of calling the checkout API directly, they behave like a real user: open the website, add items to the cart, walk through the checkout flow, and confirm that the success page appears.
This means testing the entire chain at once — frontend, backend, database, and all the services behind them. That's the core value: end-to-end tests verify that a complete user workflow actually works.

But broader coverage comes at a cost. End-to-end tests are harder to set up, slower to run, and more difficult to debug. When a unit test fails, there's only a small amount of code to investigate. When an end-to-end test fails, the problem could be hiding anywhere along the entire path.
The Testing Pyramid: Testing at the Right Level
The trade-offs between these three test types are exactly what inspired the classic concept of the "Testing Pyramid."
The general principle is: have a large number of small, fast unit tests at the base; fewer integration tests in the middle; and a small set of end-to-end tests at the top covering only the most critical workflows.
The spirit of the pyramid can be summed up in one sentence: test at the lowest level that gives us sufficient confidence. If a unit test can do the job, don't reach for a more expensive end-to-end test. This keeps feedback fast and maintenance costs under control.
The Testing Pyramid was formally introduced by Mike Cohn in his 2009 book Succeeding with Agile and later popularized by Martin Fowler and others. The anti-pattern counterpart is the "Ice Cream Cone" — a top-heavy structure packed with slow, brittle manual or end-to-end tests and almost no unit tests at the base. This leads to painfully long feedback loops: a single commit might require hours of waiting before you know whether it broke something. A notable variant of the pyramid is the "Testing Trophy," proposed by Kent C. Dodds, which advocates giving more weight to integration tests — because in modern frontend and microservices architectures, "can these modules work together?" is often closer to what users actually care about than "is this individual function logically correct?" Different teams and tech stacks may call for different shapes, but the core principle of avoiding over-reliance on high-cost tests runs through every variation.
What Changes When AI Writes the Code?
When code is generated by AI, the main changes are in speed and the sheer volume of changes. An AI agent can make a sweeping modification, generate tests for it, run those tests, fix failures, and retry — the cost of the entire loop drops dramatically.
But there's a failure mode lurking here that demands careful attention: if the same agent that wrote the implementation also writes the tests based on that implementation, it's likely to carry the same flawed assumption into both the code and the tests. The result: the code is wrong, but the tests align with the wrong code — and everything passes.

This is a particularly insidious trap. To avoid it, the definition of correct behavior must come from somewhere outside the code itself: a specification, an API contract, or a set of acceptance criteria. For significant changes, it's worth introducing an independent review step — or even a separate agent to verify the results.
The core principle: don't let the agent that built the code grade its own homework.
This failure mode maps to a classic concept in software engineering: tests should be based on specifications, not implementations. Traditional Test-Driven Development (TDD) enforces this by requiring tests to be written before the code — tests are naturally grounded in requirements, not in the implementation itself. When an AI agent takes on both the implementation and the testing roles simultaneously, it effectively breaks down the barrier that TDD was designed to create. A practical countermeasure is "specification-first": before asking AI to write any code, write out acceptance criteria in natural language or formal notation, hand those criteria to the AI to generate a test skeleton, and only then proceed to implementation. This anchors the tests in human intent rather than the AI's interpretation of that intent. Another risk worth watching is "confirmation bias amplification" — AI-generated tests tend to cover the paths the AI itself considers important, while under-covering edge cases and error flows, which is precisely where bugs love to hide.
AI Tools Are Changing the Code Review Experience
This need for independent verification has also driven the emergence of dedicated AI review tools. CodeRabbit, for example, is one of the most widely installed AI applications on GitHub and GitLab.
An AI-generated Pull Request today might change a dozen unrelated things at once, and reviewing it means jumping between countless tabs. CodeRabbit's review interface breaks the diff into small, contextually related chunks that can be examined one at a time. Click any function to see its definition inline. Ask questions about a change and get answers without leaving the page. It also flags critical sections for closer attention.

The significance of tools like this is that they make "having another party review the work" cheaper and more frictionless — a perfect fit for the AI coding era's heightened demand for independent verification.
The Unchanging Core
Ultimately, the foundational testing pyramid still holds: unit tests deliver fast feedback, integration tests catch problems at system boundaries, and end-to-end tests tell us whether an entire workflow actually runs.
AI can make building and using these feedback loops far less expensive — but it cannot define what "correct" means. That definition is, and always will be, something only we can provide.
Related articles

How Big Can Stars Really Get? The Physical Limits of the Largest Stars
Red supergiants are the largest stars by volume, with radii up to 2,000 times the Sun, engulfing the inner solar system. But there is no precise upper limit on stellar size—models predict up to 15,000 solar radii. The most massive blue stars are far smaller than red supergiants—biggest and heaviest are two different things.

Apple HomeView Smart Display Full Feature Breakdown: Wall-Mount or Desktop, $299
Apple launches HomeView, a $299 smart display with wall-mount and desktop options, 12MP camera for facial recognition, smart home control, music playback, and recipe step-by-step cooking. Full breakdown of watch faces, apps, privacy, and cooking integration.

Where Did the Promised New Studio Go? Craft Computing Answers After Five Years
Craft Computing's host responds to viewer questions: the new studio promised five years ago was shelved as construction costs soared from $30,000 to $75,000, and was replaced by a 168-square-foot garage conversion.