Software Testing Unit Testing

Unit testing is the process of testing the smallest individual pieces of code — called units — in complete isolation. A unit is usually a single function or method. The goal is to verify that each unit does exactly what it is supposed to do, on its own, before it is combined with other units.

What Is a Unit?

  A full e-commerce application has many units:

  ┌───────────────────────────────────────────────────────┐
  │  calculate_total(price, quantity)                     │
  │  apply_discount(total, discount_code)                 │
  │  validate_email(email_string)                         │
  │  format_date(date_object)                             │
  │  check_stock(product_id)                              │
  └───────────────────────────────────────────────────────┘

  Each function is a unit. Each unit is tested separately.

Why Test Units in Isolation?

When a big system fails, finding the cause is difficult if everything is connected. Testing each unit alone makes it easy to pinpoint exactly which piece of code has a problem.

  Full system test fails → "Something is wrong somewhere"
  Unit test fails        → "The calculate_discount function is broken"

Anatomy of a Unit Test

Every unit test follows the Arrange → Act → Assert pattern.

  ARRANGE: Set up the inputs and any required conditions
    price = 500
    quantity = 3

  ACT: Call the function being tested
    result = calculate_total(price, quantity)

  ASSERT: Check that the output is correct
    assert result == 1500

A Clear Unit Test Example

Function being tested: is_adult(age) — returns True if age is 18 or above, False otherwise.

  Test 1: is_adult(18) → Expected: True   → Actual: True  → PASS
  Test 2: is_adult(17) → Expected: False  → Actual: False → PASS
  Test 3: is_adult(0)  → Expected: False  → Actual: False → PASS
  Test 4: is_adult(-1) → Expected: False  → Actual: True  → FAIL ← Bug found!

Without the unit test, a negative age would be incorrectly treated as an adult. The test found this bug early, before it reached any integrated system.

Test Doubles: Mocks and Stubs

A unit must be tested in isolation. But some units depend on other components — like a database or an external payment service. Test doubles replace those dependencies so the unit can run alone.

Stub

A stub returns a fixed response when called. Instead of calling the real payment gateway, the test uses a stub that always returns "Payment approved."

  Real function: charge_card() → contacts bank server
  Stub:          charge_card() → always returns {"status": "approved"}

  The unit being tested works with the stub instead.

Mock

A mock is a more advanced stub. It also records how it was called — how many times, with what arguments — so the test can verify not just the output, but also that the right calls were made.

  Mock records:
  - Was send_email() called once? ✔
  - Was it called with the right email address? ✔
  - Was it called at all? ✔

Popular Unit Testing Frameworks

  LANGUAGE      FRAMEWORK
  ────────      ─────────
  Python        pytest, unittest
  JavaScript    Jest, Mocha
  Java          JUnit, TestNG
  C#            NUnit, xUnit
  PHP           PHPUnit
  Ruby          RSpec

Code Coverage in Unit Testing

Code coverage measures what percentage of the code is executed by unit tests. A coverage of 80% means 80% of code lines were run during testing.

  ┌─────────────────────────────────────────┐
  │ Total lines of code:     200            │
  │ Lines covered by tests:  160            │
  │ Coverage:                80%            │
  └─────────────────────────────────────────┘

High coverage does not automatically mean good tests. A test that runs every line but checks nothing is useless. Coverage is a guide, not a guarantee.

Benefits of Unit Testing

  • Bugs are found at the earliest possible stage — in individual functions.
  • Refactoring code becomes safer — existing unit tests catch regressions immediately.
  • Well-written unit tests serve as living documentation for what each function is supposed to do.
  • Developers gain confidence to make changes without fear of unknowingly breaking other parts.

Unit Testing in the Testing Pyramid

           /\
          /  \
         / UI \          ← Few, slow, expensive
        /──────\
       / Service\       ← Medium number
      /──────────\
     / Unit Tests \    ← Many, fast, cheap
    ────────────────

  Unit tests form the wide, stable base of the pyramid.

The testing pyramid recommends having many fast unit tests at the base, fewer integration tests in the middle, and a small number of end-to-end UI tests at the top. Unit tests give the most value at the lowest cost.

Leave a Comment