Skip to main content
Software Testing – Complete Beginner to Advanced Guide
CHAPTER 06 Intermediate

Unit Testing Basics

Updated: May 16, 2026
25 min read

# CHAPTER 6

Unit Testing Basics

1. Introduction

Before a car is assembled, the manufacturer tests every single bolt, gear, and wire individually. If a single gear is flawed, the entire engine will eventually fail. In software, Unit Testing is the equivalent of testing the gears. It is the lowest, most foundational level of testing, performed by Developers, not QA Engineers. A "Unit" is the smallest testable part of an application, usually a single function or method. In this chapter, we will master Unit Testing. We will explore the mechanics of Assertions, the necessity of Mocking to achieve isolation, and the revolutionary workflow known as Test-Driven Development (TDD).

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Define "Unit Testing" and explain its placement at the base of the Testing Pyramid.
  • Understand the "Arrange-Act-Assert" (AAA) testing pattern.
  • Utilize "Mocks" and "Stubs" to isolate a unit of code from external dependencies.
  • Define Test-Driven Development (TDD) and the Red-Green-Refactor cycle.
  • Read and interpret Code Coverage metrics.

3. What is a Unit Test?

A unit test evaluates a single function in absolute isolation.
  • Isolation is Key: A true unit test never connects to a real database. It never connects to the internet. It never reads a file from the hard drive. If it does any of these things, it is an Integration Test, not a Unit Test.
  • Speed: Because they do not use networks or databases, unit tests are incredibly fast. A modern project might run 5,000 unit tests in 2 seconds.

4. The Arrange-Act-Assert (AAA) Pattern

Every clean unit test follows a strict 3-step structure:
  1. 1. Arrange: Set up the initial state and data (e.g., instantiate the class, create dummy variables).
  1. 2. Act: Call the exact function you are trying to test.
  1. 3. Assert: Verify that the output of the function matches the expected result.

5. Mocking (Faking Dependencies)

How do you test a UserService->save() function without connecting to a real database? You use a Mock.
  • A Mock is a fake, programmable object. You pass the Mock into the UserService.
  • You tell the Mock: "If the Service asks you to save, just return *True* and pretend you did it."
  • This allows you to test the logic *inside* the Service without the test failing because the real database server happens to be offline.

6. Test-Driven Development (TDD)

TDD is a workflow where you write the test *before* you write the actual code.
  1. 1. Red: Write a test for a feature that doesn't exist yet. Run it. It fails (Red).
  1. 2. Green: Write the absolute minimum amount of messy code required to make the test pass (Green).
  1. 3. Refactor: Clean up the messy code. The test ensures you don't break the functionality while cleaning.

7. Code and Automation Examples

Example: PHPUnit (Testing a Calculator)
php
123456789101112131415161718
<?php
use PHPUnit\Framework\TestCase;

class CalculatorTest extends TestCase
{
    public function testAdditionReturnsCorrectSum()
    {
        // 1. Arrange
        $calculator = new Calculator();
        
        // 2. Act
        $result = $calculator->add(5, 10);
        
        // 3. Assert
        $this->assertEquals(15, $result);
    }
}
?>

8. Visual Learning: The Testing Pyramid

txt
123456
      / \       <-- UI Tests (Top: Slow, Expensive, Brittle. Have few of these.)
     /   \
    / API \     <-- Integration/API Tests (Middle: Testing connected pieces.)
   /-------\
  /  UNIT   \   <-- Unit Tests (Base: Fast, Cheap, Reliable. Have thousands of these.)
 /___________\

9. Best Practices

  • Test Behaviors, Not Implementations: Do not write a test that verifies *how* a function does its job (e.g., verifying it uses a specific while loop). Test the *output*. If you test the implementation, the test will break every time you refactor the code.

10. Common Mistakes

  • 100% Code Coverage Obsession: "Code Coverage" is a metric showing how many lines of your code were executed by unit tests. Managers often demand 100% coverage. This is a mistake. Developers will start writing meaningless tests just to hit the percentage, wasting time. Aim for 80% coverage on critical business logic.

11. Practice Exercises

  1. 1. Why must a Unit Test *never* connect to a live production database?
  1. 2. Explain the 3 steps of the TDD (Red-Green-Refactor) cycle.

12. MCQs with Answers

Question 1

What does the "Arrange" step do in the Arrange-Act-Assert (AAA) pattern?

Question 2

A developer is writing a Unit Test for a function that sends an email. To prevent the test from sending a real email to a customer, the developer uses a fake "dummy" object that simulates the email service. What is this fake object called?

13. Interview Questions

  • Q: Explain the concept of "Isolation" in Unit Testing. How do Mocks and Dependency Injection help achieve this isolation?
  • Q: Walk me through the concept of the "Testing Pyramid." Why should an application have thousands of Unit tests but only a few dozen UI tests?
  • Q: A Junior Developer argues that TDD slows them down because they have to write double the amount of code. How do you explain the long-term velocity benefits of TDD?

14. FAQs

Q: Do QA Engineers write Unit Tests? A: Generally, no. Unit testing requires deep, intimate knowledge of the application's source code architecture. It is almost exclusively the responsibility of the Software Developers. QA Engineers handle Integration, API, and UI testing.

15. Summary

In Chapter 6, we laid the foundation of automated software quality: The Unit Test. We learned that Unit Testing evaluates the smallest pieces of logic in absolute isolation, requiring the use of Mocks to fake heavy external dependencies like databases. We structured our tests using the clean Arrange-Act-Assert pattern and explored the discipline of Test-Driven Development. By building a massive, lightning-fast foundation of unit tests, developers can refactor code aggressively without fear of breaking the system.

16. Next Chapter Recommendation

The individual gears work perfectly in isolation. Now, we must assemble the engine and test if the gears actually turn together. Proceed to Chapter 7: Integration Testing.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·