Table of Contents

    Unit Testing Introduction

    Programming Mastery

    Unit Testing Introduction

    Learn how unit testing checks small parts of a program, helps find bugs early, improves code quality, and gives developers confidence while changing code.

    Introduction

    Unit testing is the process of testing a small individual part of a program to check whether it works correctly.

    A unit can be a function, method, class, module, or any small piece of logic that can be tested independently.

    Unit testing checks one small unit of code at a time.

    In real software development, unit testing is usually one of the first levels of testing. It helps developers catch problems early before the code is combined with other modules.

    Easy Real-Life Example

    Unit Testing as Checking Bicycle Parts

    Before riding a bicycle, you may check each part separately: brakes, tyres, chain, bell, and seat. If each part works correctly, the complete bicycle is more likely to work safely.

    Bicycle:
    Check brake
    Check tyre
    Check chain
    Check bell
    
    Software:
    Test login function
    Test calculation function
    Test validation function
    Test search function

    Unit testing works in the same way. It checks small parts before trusting the complete system.

    What is a Unit?

    A unit is the smallest testable part of a program.

    The exact meaning of a unit depends on the programming language and project design, but commonly it means a function, method, class, or small module.

    Unit Type Meaning Example
    Function A reusable block of logic. calculateTotal()
    Method A function inside a class or object. student.getGrade()
    Class A blueprint containing data and behavior. ShoppingCart
    Module A group of related logic. marksUtilities

    What is Unit Testing?

    Unit testing checks whether a single unit of code produces the expected result for given input.

    It usually compares the actual output of the unit with the expected output.

    Key Idea: Unit testing verifies that one small part of the program works correctly on its own.

    Simple Example

    Function:
    isPassingMark(marks)
    
    Requirement:
    Return true if marks are 40 or above.
    
    Input:
    marks = 50
    
    Expected Output:
    true
    
    Actual Output:
    true
    
    Result:
    Test Passed

    Why Unit Testing is Important

    Unit testing is important because it helps find bugs early in the development process.

    When a bug is found in a small function, it is usually easier to understand and fix than a bug found after the complete system is built.

    Benefits of Unit Testing

    • Finds bugs early.
    • Makes debugging easier.
    • Improves code quality.
    • Encourages small and focused functions.
    • Gives confidence while changing code.
    • Helps prevent old bugs from returning.
    • Makes refactoring safer.
    • Acts as basic documentation for expected behavior.
    • Supports automated testing.
    • Reduces risk before integration testing.

    Unit Testing in the Testing Levels

    Unit testing is usually the first level of software testing.

    Unit Testing
        ↓
    Integration Testing
        ↓
    System Testing
        ↓
    Acceptance Testing

    Unit testing checks individual parts. Integration testing checks how parts work together. System testing checks the full system. Acceptance testing checks whether the users accept the software.

    Example: Function to Test

    Suppose we have a function that calculates whether a student passes or fails.

    FUNCTION isPassingMark(marks)
        IF marks >= 40 THEN
            RETURN true
        ELSE
            RETURN false
        END IF
    END FUNCTION

    We can write unit tests for this function using different inputs.

    Unit Test Cases for the Function

    Test Case Input Expected Output Reason
    TC_001 marks = 50 true Marks are above passing mark.
    TC_002 marks = 40 true Boundary value for passing.
    TC_003 marks = 39 false Just below passing mark.
    TC_004 marks = 0 false Lowest possible valid mark.

    Unit Testing Process

    Unit testing can be followed as a simple step-by-step process.

    1. Identify the unit to test
    2. Understand expected behavior
    3. Prepare test data
    4. Execute the unit
    5. Compare actual result with expected result
    6. Mark test as pass or fail
    7. Fix defects if needed
    8. Re-run the test

    Expected Result vs Actual Result

    Unit testing compares what should happen with what actually happens.

    Concept Meaning Example
    Expected Result The result that should happen. For marks 50, expected result is Pass.
    Actual Result The result produced by the code. The function returns Pass.
    Test Status Pass if both match, fail if they do not. Pass when expected and actual are same.

    AAA Pattern in Unit Testing

    A common way to structure unit tests is the AAA pattern.

    AAA stands for Arrange, Act, and Assert.

    AAA Step Meaning Example
    Arrange Prepare input data and required setup. marks = 50
    Act Call the function or unit being tested. result = isPassingMark(marks)
    Assert Check whether actual result matches expected result. result should be true

    AAA Example in Pseudocode

    TEST "Marks 50 should return true"
    
        // Arrange
        marks = 50
        expectedResult = true
    
        // Act
        actualResult = isPassingMark(marks)
    
        // Assert
        CHECK actualResult == expectedResult
    
    END TEST

    The AAA pattern makes tests clean, readable, and easy to understand.

    Positive, Negative, and Boundary Unit Tests

    Good unit tests should check different types of scenarios.

    Test Type Meaning Example
    Positive Test Checks valid expected behavior. Marks 80 returns Pass.
    Negative Test Checks invalid or wrong input behavior. Marks -5 returns Invalid marks.
    Boundary Test Checks values at the edge of allowed range. Marks 40 and 39.
    Exception Test Checks whether error conditions are handled. Empty input throws validation error.

    Boundary Values in Unit Testing

    Boundary values are very important because many bugs happen near limits.

    Requirement:
    Marks must be from 0 to 100.
    
    Important unit test values:
    -1   → invalid
    0    → valid
    1    → valid
    39   → fail
    40   → pass
    100  → valid
    101  → invalid

    These values help test both valid and invalid edges.

    Manual Unit Testing vs Automated Unit Testing

    Unit testing can be done manually, but in professional projects it is commonly automated using testing frameworks.

    Manual Unit Testing Automated Unit Testing
    Developer checks function output manually. A test script checks output automatically.
    Useful for quick learning and debugging. Useful for repeated testing and large projects.
    Can be slow and inconsistent. Fast, repeatable, and reliable.
    Hard to run many tests again and again. Many tests can run automatically after code changes.

    Unit Testing Frameworks

    A unit testing framework helps developers write, run, and organize unit tests.

    Different programming languages have different testing frameworks.

    Language / Ecosystem Common Testing Framework Examples
    Java JUnit, TestNG
    Python unittest, pytest
    JavaScript Jest, Mocha, Jasmine
    .NET xUnit, NUnit, MSTest
    PHP PHPUnit

    The concept of unit testing is language-neutral, even if the tools are different.

    Example: Unit Testing a Calculator Function

    Function

    FUNCTION addNumbers(firstNumber, secondNumber)
        RETURN firstNumber + secondNumber
    END FUNCTION

    Unit Tests

    TEST "Add two positive numbers"
        // Arrange
        firstNumber = 5
        secondNumber = 3
        expectedResult = 8
    
        // Act
        actualResult = addNumbers(firstNumber, secondNumber)
    
        // Assert
        CHECK actualResult == expectedResult
    END TEST
    
    TEST "Add positive and negative number"
        // Arrange
        firstNumber = 5
        secondNumber = -3
        expectedResult = 2
    
        // Act
        actualResult = addNumbers(firstNumber, secondNumber)
    
        // Assert
        CHECK actualResult == expectedResult
    END TEST

    These tests verify that the addition function works for different inputs.

    Real-World Example: Shopping Cart Unit Tests

    In an e-commerce application, a shopping cart may have many small units to test.

    Unit Example Unit Test
    addItem() Add one product and verify cart quantity.
    calculateSubtotal() Verify total price before discount and tax.
    applyDiscount() Apply 10% discount and verify final amount.
    clearCart() Clear all items and verify cart becomes empty.
    validateQuantity() Reject quantity less than 1.

    Student-Friendly Example: Grade Calculator Unit Tests

    Function:
    calculateGrade(marks)
    
    Rules:
    90 to 100 → A
    75 to 89  → B
    60 to 74  → C
    40 to 59  → D
    Below 40  → Fail
    Invalid if marks are below 0 or above 100
    
    Unit Test Cases:
    marks = 95  → A
    marks = 75  → B
    marks = 60  → C
    marks = 40  → D
    marks = 39  → Fail
    marks = -1  → Invalid
    marks = 101 → Invalid

    This example includes normal values, boundary values, and invalid values.

    Unit Tests Should Be Isolated

    A unit test should focus on one unit and avoid depending on unrelated systems.

    If a unit test depends on a database, external API, network, or full user interface, it may become slow and unreliable.

    Simple Rule: A unit test should test one small unit in isolation.

    Characteristics of Good Unit Tests

    Good unit tests should be easy to run, easy to understand, and reliable.

    Good Unit Tests Should Be

    • Small: Test one behavior at a time.
    • Fast: Run quickly so developers can run them often.
    • Independent: Do not depend on other tests.
    • Repeatable: Same input should produce same result.
    • Readable: Easy to understand from the test name and structure.
    • Automated: Can be executed by a testing tool.
    • Focused: Test one clear condition or behavior.

    What Unit Testing Can and Cannot Find

    Unit testing is powerful, but it does not replace all other testing.

    Unit Testing Can Find Unit Testing May Not Find
    Wrong calculation logic. Problems between multiple modules.
    Incorrect validation rule. Full system workflow issues.
    Boundary value mistakes. User interface layout issues.
    Unexpected function output. Real database or network integration problems.

    That is why unit testing should be combined with integration, system, acceptance, and regression testing.

    Unit Testing and Regression Safety

    Unit tests help protect existing behavior when code changes.

    If a developer refactors a function and accidentally breaks it, a unit test can fail immediately and alert the developer.

    Before change:
    calculateDiscount(1000, 10) → 100
    
    After refactoring:
    Unit test still checks:
    calculateDiscount(1000, 10) should return 100
    
    If result changes unexpectedly:
    Test fails

    This gives developers confidence when improving or refactoring code.

    Unit Testing and TDD

    TDD stands for Test-Driven Development.

    In TDD, developers write tests before writing the actual implementation code.

    TDD Flow:
    1. Write a failing test
    2. Write minimum code to pass the test
    3. Refactor the code
    4. Run tests again

    Beginners do not need to master TDD immediately, but they should understand that unit tests can also guide software design.

    Common Beginner Mistakes in Unit Testing

    Mistakes

    • Testing only one happy path.
    • Ignoring negative and boundary cases.
    • Writing unclear test names.
    • Testing too many things in one test.
    • Depending on external systems unnecessarily.
    • Not updating tests when requirements change.
    • Not running tests after code changes.
    • Writing tests that are difficult to understand.

    Better Habits

    • Test one behavior at a time.
    • Use clear test names.
    • Follow Arrange, Act, Assert.
    • Include positive, negative, and boundary cases.
    • Keep tests independent.
    • Run tests after every important change.
    • Write simple and readable tests.
    • Fix failing tests carefully.

    Best Practices for Unit Testing

    Recommended Practices

    • Write tests for important business logic.
    • Use meaningful test names.
    • Follow the AAA pattern.
    • Keep each test small and focused.
    • Test normal, invalid, and boundary inputs.
    • Make tests independent from each other.
    • Avoid unnecessary external dependencies.
    • Run unit tests frequently.
    • Use automated testing frameworks when possible.
    • Review failed tests carefully.
    • Update tests when requirements change.
    • Use unit tests as a safety net during refactoring.

    Prerequisites Before Learning Unit Testing

    Students should understand the following topics before learning unit testing deeply:

    Required Knowledge

    • Basic programming syntax.
    • Variables and data types.
    • Control flow and loops.
    • Functions or methods.
    • Return values.
    • Input and output concepts.
    • Testing basics.
    • Clean code basics.
    • Debugging basics.

    Trace Table Example: Unit Testing a Discount Function

    FUNCTION calculateDiscount(amount, discountPercentage)
        RETURN amount * discountPercentage / 100
    END FUNCTION
    Test Case Amount Discount % Expected Discount
    TC_001 1000 10 100
    TC_002 500 0 0
    TC_003 200 50 100
    TC_004 0 10 0

    Practice Activity: Write Unit Tests

    Write unit test cases for the following function.

    FUNCTION isEven(number)
        IF number MOD 2 == 0 THEN
            RETURN true
        ELSE
            RETURN false
        END IF
    END FUNCTION

    Sample Unit Test Cases

    Test Case 1:
    number = 2
    Expected Result: true
    
    Test Case 2:
    number = 3
    Expected Result: false
    
    Test Case 3:
    number = 0
    Expected Result: true
    
    Test Case 4:
    number = -4
    Expected Result: true
    
    Test Case 5:
    number = -7
    Expected Result: false

    Mini Quiz

    1

    What is unit testing?

    Unit testing is the process of testing a small individual part of code, such as a function or method, to check whether it works correctly.

    2

    What is a unit in unit testing?

    A unit is the smallest testable part of a program, such as a function, method, class, or module.

    3

    What does AAA stand for?

    AAA stands for Arrange, Act, and Assert.

    4

    Why is unit testing useful?

    Unit testing is useful because it finds bugs early, makes debugging easier, improves code quality, and gives confidence during code changes.

    5

    What should a good unit test check?

    A good unit test should check one clear behavior using valid, invalid, and boundary input where appropriate.

    Interview Questions on Unit Testing Introduction

    1

    What is the purpose of unit testing?

    The purpose of unit testing is to verify that individual units of code work correctly before they are combined with other parts of the system.

    2

    What is the difference between unit testing and integration testing?

    Unit testing checks one small unit in isolation, while integration testing checks whether multiple units or modules work correctly together.

    3

    Why should unit tests be independent?

    Unit tests should be independent so that one test does not depend on another test’s result or execution order.

    4

    What is the AAA pattern?

    The AAA pattern is a structure for unit tests where Arrange prepares data, Act executes the unit, and Assert checks the expected result.

    5

    Why are boundary cases important in unit testing?

    Boundary cases are important because many bugs occur near minimum, maximum, or decision-changing values.

    Quick Summary

    Concept Meaning
    Unit Testing Testing a small individual part of code.
    Unit A function, method, class, or module that can be tested.
    Expected Result The result that should happen.
    Actual Result The result produced by the code.
    AAA Pattern Arrange, Act, Assert structure for writing tests.
    Boundary Test Testing values near limits or decision points.
    Automated Unit Test A test executed automatically by a testing framework.
    Regression Safety Unit tests help detect if old behavior breaks after changes.

    Final Takeaway

    Unit testing is a foundational software testing practice where small parts of code are tested independently. It helps developers find bugs early, improve code quality, test boundary cases, and safely change or refactor code. A good unit test is small, fast, independent, readable, and focused on one behavior. Students should learn to write unit tests using clear test cases, expected results, and the Arrange-Act-Assert pattern.