Unit testing is the practice of testing the smallest pieces of code, typically a single function or method, in isolation from the rest of the application. It exists to catch a defect in one small piece before it's buried under the layers of code and other tests built on top of it.

A "unit" is usually the smallest piece of code that does one identifiable thing, a function that calculates a discount, a method that validates an email address, a component that formats a date. Unit testing checks that piece on its own, feeding it a range of inputs and confirming it returns the output it should, without involving a database, a network call, or any other part of the system it might normally run alongside.

That isolation is the point. To test a function on its own, its dependencies get replaced with stand-ins, mocks or stubs that return a fixed, predictable value instead of doing the real work a database query or an API call would do. That keeps a unit test fast and focused: it fails because the function itself has a bug, not because a database happened to be slow or unavailable when the test ran.

Because unit tests are small, isolated, and fast, teams tend to write a lot of them, far more than integration or end-to-end tests, and run them constantly, often on every save or every commit. That's the idea behind the testing pyramid: a large base of quick unit tests, a smaller layer of integration tests above it, and a thin top layer of slower end-to-end tests, so most defects get caught at the cheapest, fastest layer before they ever reach the slower ones.


How unit testing works

  • Isolate the unit, usually a single function or method, from the rest of the codebase.
  • Replace its external dependencies with mocks or stubs that return a fixed, predictable value.
  • Feed it a range of inputs, including typical cases, edge cases, and invalid ones.
  • Assert that the output matches what's expected for each input.
  • Run the suite frequently, often on every save or commit, since each test is small and quick.

Where it shows up

  • Checking that a pricing function returns the right total across normal, zero, and negative inputs.
  • Confirming a validation function correctly accepts or rejects a range of email formats.
  • Writing a test alongside a bug fix that reproduces the original defect, so it can't silently come back.
  • Using test-driven development, where the unit test is written before the code it's meant to check.

Benefits and challenges

BenefitChallenge
Runs in seconds, so a developer gets feedback on a change almost immediately. Only tests one piece in isolation, and can't catch a defect that only shows up when pieces interact.
Pinpoints a defect to a specific function, rather than leaving a team to trace a failure through the whole system. Mocking every dependency takes real setup work, and a test built around the wrong mock can pass while the real integration still fails.
Makes refactoring safer, since a passing suite is a quick way to confirm behavior didn't change. A suite tied too closely to implementation details breaks on every refactor, even ones that don't change behavior at all.

Frequently asked questions

How is unit testing different from integration testing?

Unit testing checks one piece of code on its own, with its dependencies replaced by mocks. Integration testing checks that separate pieces, like a function and the database it actually queries, work correctly together. A codebase generally needs both, since neither one catches what the other is built for.

Does a project need 100% unit test coverage?

Not necessarily. Coverage is a useful signal, but a high percentage doesn't guarantee the tests check anything meaningful, and chasing the last few percent on rarely-touched code often isn't worth the time. Most teams aim for solid coverage on the logic that's complex or changes often, rather than a specific number everywhere.

What is test-driven development?

Test-driven development, or TDD, is writing the unit test for a piece of behavior before writing the code that makes it pass. The idea is that designing the test first forces clearer thinking about what the function should actually do, and leaves a passing suite as a byproduct of the work rather than an afterthought.


How Klarent helps

Klarent's AI agents work higher up the testing pyramid, generating and maintaining the end-to-end and regression tests that sit above a project's unit tests, covering full user flows that a unit test in isolation was never meant to catch.


Ready to eliminate QA bottlenecks? Talk to our team for a personalised walkthrough.

Book a free 30 minute call