Unit Testing in Software Engineering: Process, Techniques, Types & Examples

Software Engineering • Chapter 26

Unit Testing in Software Engineering: Process, Techniques, Types & Examples

When a large software application fails, the problem is usually not created by the complete application as one single block. Software is made from smaller functions, methods, classes, modules, and components. If these small units are tested correctly before they are combined, many defects can be discovered much earlier. This is the basic idea behind Unit Testing. Unit Testing focuses on the smallest practical testable parts of software and checks whether each part behaves correctly for normal input, boundary values, invalid input, exceptional situations, and other important conditions.
Direct Answer Unit Testing is a software testing level in which an individual unit or component of software is tested, usually in isolation from other components, to verify that its behaviour is correct. A unit may be a function, method, class, module, or another small component, depending on the programming language and software design. In modern testing terminology, Unit Testing is also commonly called Component Testing.

What is Unit Testing?

Unit Testing in Software Engineering: Process, Techniques, Types & Examples

Unit Testing tests individual software units separately so that defects can be found close to the part of the code where they were introduced.

Suppose an online shopping application contains:

  • Login function
  • Tax calculation function
  • Discount calculation function
  • Payment module
  • Order module

Instead of waiting for the complete application to be ready, developers can test the discount function separately.

calculateDiscount(1000, true)

If a premium customer should receive a 10% discount, the expected output may be:

Expected Result = 900

If the function returns 900, that particular test passes. If it returns 1000 or another incorrect value, the test fails.

What is a Unit in Unit Testing?

A unit does not always mean exactly one line of code.

The meaning depends on the programming language, architecture, and testing approach.

Function

A small independent function such as calculateTax().

Method

A method belonging to an object or class.

Class

A class whose public behaviour is tested as a small component.

Module

A small cohesive software module containing related behaviour.

Where Does a Unit Fit?
Complete Software System
Module / Component
Function / Method / Small Unit

Objectives of Unit Testing

Verify Correct Logic

Check whether the unit produces the expected output for a given input.

Find Defects Early

Detect logical errors before components are combined into larger systems.

Check Boundary Behaviour

Test minimum, maximum, zero, empty, and edge values.

Check Error Handling

Verify whether invalid or exceptional conditions are handled correctly.

Support Refactoring

A good unit test suite can provide quick feedback when internal code is changed.

Prevent Regression

Previously tested behaviour can be checked again after new changes.

Improve Design Feedback

Code that is very difficult to unit test may reveal excessive coupling or hidden dependencies.

Document Behaviour

Well-written unit tests can show how a function or class is expected to behave.

Provide Fast Feedback

Small isolated tests can usually execute quickly during development.

Why is Unit Testing Important?

Without Unit Testing, developers may discover a defect only after many components have been integrated.

At that stage, finding the exact source of the problem may become more difficult.

Early Detection Flow
Write Small Unit
→
Execute Unit Tests
→
Detect Failure
→
Fix Local Defect
→
Run Tests Again
Simple Idea If the failure appears immediately after a small function is changed, developers have a much smaller area to investigate than when the same failure is discovered only after the complete application is deployed.

Who Performs Unit Testing?

Unit Testing is commonly performed by developers because they understand the internal implementation and normally have access to the source code.

Automated unit tests are often written along with the production code and executed repeatedly during development.

Modern Terminology Unit Testing is also called Component Testing. It normally focuses on testing individual components in isolation and may use a test framework, test harness, stub, mock, fake, or other support code.

Unit Testing Process

A systematic Unit Testing process is better than randomly trying input values.

1
Understand the Unit Identify what the function, method, class, or module is supposed to do. Study its inputs, outputs, preconditions, postconditions, error conditions, and dependencies.
2
Identify Test Conditions Determine which situations need checking. Examples include normal input, minimum value, maximum value, zero, empty input, invalid values, and exceptional behaviour.
3
Prepare the Test Environment Prepare the test framework, fixture, input data, test doubles, configuration, and other required resources.
4
Write Unit Test Cases Define input, expected result, execution action, and assertion for each important behaviour.
5
Execute the Unit Call the unit using the selected input and observe the actual result.
6
Compare Actual and Expected Results Use assertions to determine whether the unit behaved correctly.
7
Investigate Failures If a test fails, determine whether the production code, test code, requirement, or test data contains the problem.
8
Fix and Run Again Correct the defect and execute the relevant unit tests again.
9
Run the Full Unit Test Suite Check whether the latest change affected any previously working behaviour.

Arrange-Act-Assert Pattern

One of the easiest ways to structure a unit test is the Arrange-Act-Assert pattern.

A Arrange

Prepare input data, objects, dependencies, and expected values.

A Act

Execute the function or method being tested.

A Assert

Compare the actual result with the expected result.

Simple AAA Example

// Arrange let price = 1000; let discount = 100; // Act let result = price - discount; // Assert result should equal 900;
Memory Trick AAA = Arrange → Act → Assert Prepare → Execute → Verify

Types of Unit Testing

Unit Testing can be classified in different ways depending on the purpose and testing approach.

1. Manual Unit Testing

A developer manually executes or checks a small unit without maintaining a repeatable automated test script.

This may be useful for quick investigation, but it becomes inefficient when tests must be repeated frequently.

2. Automated Unit Testing

Test code is written using a testing framework and executed automatically.

This is especially useful for:

  • Regression testing
  • Repeated builds
  • Continuous Integration
  • Large collections of unit tests
  • Fast developer feedback

3. Positive Unit Testing

Checks expected behaviour using valid input.

Example:

calculateSquare(5) → 25

4. Negative Unit Testing

Checks behaviour when invalid or unexpected input is provided.

Example:

withdraw(-500) → Reject Invalid Amount

5. Exception Testing

Checks whether expected exceptions or error conditions are produced correctly.

Example:

divide(10, 0) → Error / Exception

6. State-Based Unit Testing

Checks the state of an object before and after an operation.

Example:

account.deposit(500) Expected: account.balance = previousBalance + 500

7. Interaction-Based Unit Testing

Checks whether a unit interacts with its dependency correctly.

For example, a service method may be expected to call a repository exactly once with specific data.

8. Parameterized Unit Testing

The same test logic is executed using multiple sets of input and expected output.

Input Expected Square
2 4
3 9
5 25
10 100

Unit Testing Techniques

Good unit tests are selected using testing techniques rather than random values.

Statement Testing

Design tests to execute statements in the unit.

Branch Testing

Design tests to exercise decision outcomes such as true and false branches.

Condition Testing

Check individual Boolean conditions in logical expressions.

Boundary Value Analysis

Test values near important input boundaries.

Equivalence Partitioning

Divide possible input into groups expected to behave similarly.

Error Guessing

Use experience to predict likely problem cases.

White-Box Unit Testing Techniques

Unit Testing is often performed with knowledge of the source code, so white-box techniques are especially useful.

Statement Coverage

Checks whether executable statements have been executed by the tests.

function checkNumber(n) { if (n > 0) { return "Positive"; } return "Zero or Negative"; }

Testing only:

checkNumber(5)

does not exercise the second return path in all logical situations.

Branch Testing

Every decision outcome should be tested.

For the previous example, useful tests include:

Input Branch Expected Output
5 True Positive
-2 False Zero or Negative

Condition Testing

Consider:

if (age >= 18 && hasID) { allowEntry(); }

The two important Boolean conditions are:

  • age >= 18
  • hasID

Tests should consider meaningful true and false combinations.

Loop Testing

When a unit contains loops, useful test conditions may include:

  • Zero iterations
  • One iteration
  • Typical number of iterations
  • Boundary number of iterations
  • Large permitted iteration count

Path Testing

Different control-flow paths through the unit are identified and selected for testing.

For complex units, Cyclomatic Complexity can help identify the number of linearly independent basis paths.

Black-Box Techniques at Unit Level

Even when source code is available, input-output based techniques can still be useful at unit level.

Equivalence Partitioning Example

Suppose a function accepts marks from 0 to 100.

Invalid Partition

marks < 0

Valid Partition

0–100

Invalid Partition

marks > 100

Boundary Value Analysis Example

For a valid range of 0–100, useful values include:

-1, 0, 1, 99, 100, 101

Decision Table Testing

This can be useful when a unit contains several business-rule combinations.

Condition Rule 1 Rule 2 Rule 3 Rule 4
Premium Customer? Yes Yes No No
Order > ₹1000? Yes No Yes No
Discount 20% 10% 5% 0%

What is a Test Fixture?

A test fixture is the known environment or state required for a test.

It may contain:

  • Objects
  • Initial values
  • Test accounts
  • Temporary data
  • Mock dependencies
  • Configuration

Setup and Teardown

Many test frameworks provide setup and teardown operations.

Setup Create clean test state
→
Run Test Execute unit behaviour
→
Assert Verify result
→
Teardown Clean temporary resources
Why Fixtures Matter Each unit test should ideally start from a known state so that one test does not accidentally depend on another test.

What are Test Doubles?

A unit may depend on another object, database, API, file system, clock, payment service, email service, or network connection.

Using the real dependency may make a unit test slow, unpredictable, or no longer truly isolated.

A test double replaces a real dependency during testing.

Dummy

Dummy Object

An object passed only because a parameter is required but whose behaviour is not actually used by the test.

Stub

Stub

Returns predefined data when the unit calls a dependency.

Example: always return a fixed customer record.

Fake

Fake

A simplified working implementation used instead of the real production dependency.

Example: in-memory repository instead of a real database.

Spy

Spy

Records information about calls so the test can later check how the dependency was used.

Mock

Mock

A controlled replacement with predefined interaction expectations that can be verified by the test.

Stub vs Mock

Basis Stub Mock
Main Purpose Provide controlled responses Verify expected interactions
Main Question What should the dependency return? Was the dependency called correctly?
Example Return user ID 10 Verify save() was called once

Stubs and Drivers in Unit Testing

Traditional Software Engineering books often explain unit testing using stubs and drivers.

Stub

Stub

A temporary replacement for a lower-level module or dependency called by the unit under test.

It returns controlled results.

Driver

Driver

A temporary program that calls the unit being tested when the real calling module is not yet available.

Driver and Stub Relationship
Driver Calls the unit
→
Unit Under Test
→
Stub Simulates dependency

Dependency Isolation

Isolation is one of the most important ideas in Unit Testing.

Suppose an OrderService directly uses:

  • Real database
  • Real payment gateway
  • Real email server

If all these real services are required for a test, the test has moved closer to integration testing.

For a focused unit test, these external dependencies can often be replaced with controlled test doubles.

Dependency Injection

Dependency Injection makes testing easier by allowing dependencies to be supplied from outside rather than being created secretly inside the unit.

class OrderService { constructor(paymentService) { this.paymentService = paymentService; } placeOrder(order) { return this.paymentService.pay(order.total); } }

During production, a real payment service can be supplied.

During unit testing, a fake or mock payment service can be supplied.

How to Design a Unit Test Case

A good unit test should clearly state what behaviour is being checked.

Test Case ID
UT-DISCOUNT-01
Unit
calculateDiscount()
Input
Amount = 1000, Premium = true
Expected Output
900
Condition
Premium customer receives 10% discount
Result
Pass if actual output is 900

Complete Unit Testing Example

Example: Discount Calculation Unit

Production Function

function calculateDiscount(amount, isPremium) { if (amount < 0) { throw new Error("Invalid amount"); } if (isPremium) { return amount * 0.90; } return amount; }

Test 1: Premium Customer

// Arrange const amount = 1000; const isPremium = true; // Act const result = calculateDiscount(amount, isPremium); // Assert result should equal 900;

Test 2: Normal Customer

calculateDiscount(1000, false) Expected Result = 1000

Test 3: Zero Amount

calculateDiscount(0, true) Expected Result = 0

Test 4: Negative Amount

calculateDiscount(-100, true) Expected Result = Error "Invalid amount"

What Did These Tests Cover?

  • Normal premium behaviour
  • Normal non-premium behaviour
  • Zero boundary condition
  • Invalid negative input
  • Exception behaviour

Unit Testing of Functions with Multiple Conditions

function canVote(age, isCitizen) { if (age >= 18 && isCitizen) { return true; } return false; }

Useful test cases include:

Age Citizen? Expected Result
20 Yes True
17 Yes False
20 No False
18 Yes True

Code Coverage in Unit Testing

Code coverage measures how much of the program structure was exercised while tests were executed.

Coverage is useful, but it must be interpreted carefully.

Statement Coverage Percentage of executable statements exercised.
Branch Coverage Percentage of decision outcomes exercised.
Function Coverage Percentage of defined functions executed.

Statement Coverage Formula

Statement Coverage = Executed Statements / Total Statements × 100

Branch Coverage Formula

Branch Coverage = Executed Branches / Total Branches × 100

Example

Suppose a function contains 20 executable statements and tests execute 18 of them.

Statement Coverage = 18 / 20 × 100 = 90%
Very Important 100% code coverage does not mean the software is defect-free. A test can execute a line without checking the correct result. Coverage tells us what was exercised. Assertions and test quality tell us whether behaviour was actually verified.

Cyclomatic Complexity and Unit Testing

Cyclomatic Complexity can help identify the number of independent paths in a unit's control-flow graph.

M = E - N + 2P

For a single connected function, another simple representation is often:

Cyclomatic Complexity ≈ Decision Points + 1

If a function has many decision points, it may require more tests to exercise different branches and paths.

Testing Connection A highly complex unit may need more test cases, but Cyclomatic Complexity should not be treated as the only measure of test quality.

Test-Driven Development (TDD)

Test-Driven Development is a development approach in which a test is written before the production code required to make that test pass.

RED
Write a failing test
→
GREEN
Write minimum code to pass
→
REFACTOR
Improve the code

Step 1: Red

Write a test for behaviour that does not yet exist.

The test should fail.

Step 2: Green

Write enough production code to make the test pass.

Step 3: Refactor

Improve the code structure while keeping the tests passing.

Memory Trick TDD = Red → Green → Refactor

Unit Testing vs TDD

Unit Testing and TDD are related but they are not the same.

Basis Unit Testing TDD
Meaning Testing individual software units Development approach driven by tests
When Test is Written Before or after production code Normally before corresponding production code
Main Focus Verify unit behaviour Guide design and implementation through tests

Unit Testing and the Test Pyramid

The Test Pyramid is a common testing heuristic that encourages a large base of fast small tests, fewer integration tests, and fewer broad end-to-end tests.

End-to-End / UI Tests
Integration Tests
Unit Tests

The exact balance depends on the project. The pyramid should be treated as a useful design idea rather than a fixed universal percentage.

Automated Unit Testing

Unit Testing is especially suitable for automation because individual units can often be tested quickly and repeatedly.

A typical automated flow is:

Developer Changes Code
→
Unit Tests Run
→
Pass / Fail Result
→
Fix if Required
→
Commit / Build

Unit Tests in CI/CD

Automated unit tests are often executed during Continuous Integration.

If an important test fails, the build or pipeline can be stopped before the defective change moves further through delivery stages.

Advanced Unit Testing Concepts

1. Parameterized Testing

One test definition is executed using multiple input-output combinations.

This reduces repetitive test code while improving data coverage.

2. Data-Driven Testing

Test data is separated from test logic and may come from a table, file, object, or generated dataset.

3. Property-Based Testing

Instead of checking only a few fixed examples, a general property is defined and many input values are generated automatically.

Example property:

absoluteValue(x) should never be negative

4. Mutation Testing

Mutation Testing evaluates the strength of tests by intentionally making small changes to production code.

For example:

Original: if (age >= 18) Mutant: if (age > 18)

If existing unit tests detect the changed behaviour, the mutant is killed.

If all tests still pass, the test suite may be missing an important case such as age exactly 18.

Mutation Score = Killed Valid Mutants / Total Valid Mutants × 100

5. Characterization Testing

When working with legacy code whose behaviour is poorly documented, characterization tests can record the current observable behaviour before major refactoring begins.

6. Testing Asynchronous Code

Modern software often contains asynchronous operations such as promises, tasks, callbacks, and asynchronous functions.

Unit tests should wait correctly for the asynchronous operation and verify both successful and failed outcomes.

7. Testing Time-Dependent Code

Code depending directly on the current date or time can create unstable tests.

A controllable clock or injected time provider can make the test deterministic.

8. Testing Random Behaviour

Random values can make results difficult to reproduce.

Tests can control randomness by injecting a random-number provider or using a fixed seed where appropriate.

9. Floating-Point Testing

Floating-point calculations may contain tiny precision differences.

Instead of always checking exact equality, tests may compare values using a small acceptable tolerance.

Testing Object-Oriented Classes

For object-oriented programs, useful Unit Testing areas include:

  • Constructor behaviour
  • Public methods
  • Object state changes
  • Boundary conditions
  • Exceptions
  • Interactions with dependencies
  • Inheritance or polymorphic behaviour where relevant
Private Methods Private methods are implementation details. In many designs, it is better to verify them indirectly through the public behaviour of the class instead of creating tests tightly coupled to private implementation details.

Testing Procedural Programs

In procedural programming, a unit may be a function or procedure.

Tests should check:

  • Input values
  • Return values
  • Output parameters
  • State changes
  • Side effects
  • Error handling
  • Boundary conditions

Characteristics of Good Unit Tests

A useful memory rule is FIRST.

F – Fast

Unit tests should generally execute quickly so developers can run them often.

I – Independent

One test should not depend on another test running first.

R – Repeatable

The same conditions should produce the same result repeatedly.

S – Self-Validating

The test should clearly determine pass or fail using assertions.

T – Timely

Tests should be written close to the time when the related behaviour is created.

Other Good Qualities

  • Readable
  • Focused
  • Deterministic
  • Maintainable
  • Meaningful test names
  • Clear failure messages
  • Small amount of setup
  • Checks useful behaviour

How Should Unit Tests Be Named?

Test names should explain the situation and expected behaviour.

calculateDiscount_premiumCustomer_returnsTenPercentDiscount divide_zeroDenominator_throwsError login_invalidPassword_returnsFailure

A descriptive test name makes failures easier to understand.

One Behaviour Per Test

A unit test should normally focus on one clearly defined behaviour or reason for failure.

This does not mean every test must contain only one assertion.

Several related assertions may be acceptable when they verify one logical behaviour.

Common Unit Testing Mistakes

Testing Too Much at Once

If the test uses the real database, network, email service, and payment gateway, it may no longer be a focused unit test.

Testing Implementation Instead of Behaviour

Tests that depend heavily on private internal details can break during harmless refactoring.

No Negative Tests

Testing only valid values leaves invalid and exceptional behaviour unchecked.

Shared Mutable State

One test changing data required by another test can create unpredictable results.

Flaky Tests

A test that sometimes passes and sometimes fails without a relevant code change reduces trust in the suite.

Over-Mocking

Mocking every internal detail can create tests that are difficult to maintain and too closely tied to implementation.

Chasing Coverage Numbers Only

High coverage without meaningful assertions may give false confidence.

Ignoring Test Code Quality

Unit tests are also software and should remain readable and maintainable.

What is a Flaky Unit Test?

A flaky test produces inconsistent results without a meaningful change in the code being tested.

Common causes include:

  • Current time dependency
  • Random data
  • Shared global state
  • Thread timing
  • Network dependency
  • Real external service
  • Uncontrolled database data
  • Test execution order dependency

What Should Not Normally Be a Unit Test?

If the purpose of a test is specifically to verify the real interaction between several components or external systems, it belongs more naturally to integration or system testing.

Examples include:

  • Real database connectivity
  • Actual payment gateway integration
  • Complete browser workflow
  • Real API-to-API communication
  • Full application deployment

Unit Testing vs Integration Testing vs System Testing

Basis Unit Testing Integration Testing System Testing
Scope Individual unit/component Interaction between components Complete system
Main Purpose Verify local behaviour Verify interfaces and interactions Verify complete system behaviour
Typical Performer Developers Developers/testers depending on project Testing team or relevant project team
External Dependencies Often isolated Usually some real integrations Large part of complete system
Execution Speed Usually fast Usually slower than unit tests Often slower and more complex
Example calculateTax() Order Service + Database Complete shopping application

Unit Testing vs Regression Testing

These terms describe different ideas.

Unit Testing describes the level or scope of the test.

Regression Testing describes the purpose of repeating tests after change.

Therefore, automated unit tests can become part of a regression test suite.

Unit Testing vs Debugging

Unit Testing

Executes tests to reveal incorrect behaviour in a small unit.

Debugging

Investigates the cause of a failure and modifies the code to correct the defect.

Advantages of Unit Testing

Early Defect Detection

Problems can be discovered close to the code where they were introduced.

Fast Feedback

Small automated tests can usually run frequently during development.

Supports Refactoring

Tests can detect unintended behaviour changes during internal restructuring.

Improves Regression Safety

Existing tests can be rerun after changes.

Improves Modularity Feedback

Difficult-to-test code can reveal excessive coupling or hidden dependencies.

Useful Documentation

Tests can show examples of expected behaviour.

Limitations of Unit Testing

Cannot Find Every Integration Problem

Units may work individually but fail when connected.

Cannot Replace System Testing

Unit tests do not verify the complete user workflow.

Maintenance is Required

Tests need updates when valid behaviour or interfaces change.

Poor Tests Give False Confidence

Many weak tests are not automatically better than fewer meaningful tests.

External Quality Needs Other Tests

Performance, usability, deployment, and real integration behaviour require other testing approaches.

Coverage is Not Correctness

Executing code does not automatically prove the result is correct.

Best Practices for Unit Testing

  1. Keep each unit test focused.
  2. Use meaningful test names.
  3. Test both positive and negative cases.
  4. Test important boundary values.
  5. Keep tests independent.
  6. Avoid uncontrolled external dependencies.
  7. Use clear assertions.
  8. Keep tests deterministic.
  9. Run unit tests frequently.
  10. Fix failing tests rather than ignoring them.
  11. Refactor duplicated test code carefully.
  12. Do not chase coverage percentage without useful assertions.
  13. Use mocks and stubs only where they provide value.
  14. Keep production behaviour and test expectations understandable.

Common Unit Testing Metrics

Test Pass Rate

Passed Tests / Executed Tests × 100

Statement Coverage

Executed Statements / Total Statements × 100

Branch Coverage

Executed Branches / Total Branches × 100

Example

Suppose:

  • 100 unit tests executed
  • 96 passed
  • 4 failed
Pass Rate = 96 / 100 × 100 = 96%

Unit Testing in Agile Development

In Agile development, developers frequently create and change small pieces of functionality during short iterations.

Unit tests can provide quick feedback after these changes.

User Story
→
Implement Small Change
→
Run Unit Tests
→
Refactor
→
Continuous Feedback

Unit Testing in DevOps

Unit tests are commonly placed early in automated build pipelines because they can provide fast feedback before slower test stages are executed.

Code Commit
→
Build
→
Unit Tests
→
Integration Tests
→
Other Pipeline Checks

Common Student Confusions

Confusion 1: Unit Testing Means Testing One Line A unit normally means a small testable software component such as a function, method, class, or module, not necessarily one line.
Confusion 2: Unit Testing and Integration Testing Are Same Unit Testing checks a unit in isolation. Integration Testing checks interaction between units or components.
Confusion 3: Stub and Driver Are Same A stub is typically called by the unit under test. A driver calls the unit under test.
Confusion 4: 100% Coverage Means Perfect Testing Coverage does not tell whether assertions are meaningful or whether every important requirement has been tested.
Confusion 5: TDD and Unit Testing Are Identical Unit Testing is a testing level. TDD is a development approach that uses tests to guide implementation.

Memory Tricks

AAA Arrange → Act → Assert
FIRST Fast
Independent
Repeatable
Self-validating
Timely
TDD Red → Green → Refactor

Important Exam Questions

Q1. What is Unit Testing? Unit Testing is a level of software testing in which individual units or components are tested, usually in isolation, to verify that they behave correctly.
Q2. Who normally performs Unit Testing? Unit Testing is commonly performed by developers because they have knowledge of the internal implementation and source code.
Q3. What is a Stub? A stub is a temporary or controlled replacement for a dependency called by the unit under test.
Q4. What is a Driver? A driver is a temporary program or component that calls the unit under test when the actual calling module is unavailable.
Q5. What is the AAA pattern? AAA means Arrange, Act and Assert. First prepare the test state, then execute the unit, and finally verify the result.
Q6. What is code coverage? Code coverage measures how much of a selected program structure, such as statements or branches, was exercised during testing.
Q7. What is TDD? Test-Driven Development is a development approach where a failing test is written before the production code needed to satisfy that test, followed by code improvement through refactoring.

Important 5-Mark Question

Explain the Unit Testing process. For a good 5-mark answer, explain:
  1. Understand the unit.
  2. Identify test conditions.
  3. Prepare test data and environment.
  4. Create unit test cases.
  5. Execute tests.
  6. Compare actual and expected results.
  7. Fix defects.
  8. Run tests again.
Also mention that Unit Testing is generally performed by developers.

Important 10-Mark Question

Explain Unit Testing with process, techniques, stubs, drivers, advantages and examples. Structure the answer as:
  1. Definition
  2. Objectives
  3. Unit Testing process
  4. White-box techniques
  5. Boundary and equivalence testing
  6. Stub and driver
  7. Test doubles
  8. Code coverage
  9. Advantages
  10. Limitations
  11. Suitable example

Quick Revision Notes

Unit Testing:
Testing individual software units
Modern Name:
Component Testing
Usually Performed By:
Developers
Main Goal:
Verify local unit behaviour
AAA:
Arrange → Act → Assert
Stub:
Provides controlled dependency response
Driver:
Calls the unit under test
Mock:
Checks expected interaction
Fixture:
Known test state/environment
Positive Test:
Valid expected input
Negative Test:
Invalid or unexpected input
Boundary Testing:
Check values around limits
Statement Coverage:
Executed statements percentage
Branch Coverage:
Executed decision outcomes percentage
TDD:
Red → Green → Refactor
FIRST:
Fast, Independent, Repeatable, Self-validating, Timely

Frequently Asked Questions

What is Unit Testing in Software Engineering?

Unit Testing tests individual functions, methods, classes, or components, normally in isolation, to verify that their behaviour is correct.

Is Unit Testing the same as Component Testing?

Yes. Modern testing terminology commonly uses Component Testing for the testing level traditionally called Unit Testing.

Who performs Unit Testing?

Unit Testing is commonly performed by developers because they usually understand the internal source code and implementation.

What is the difference between a stub and a mock?

A stub mainly provides predefined responses to the unit, while a mock is commonly used to verify whether expected interactions occurred.

What is the difference between Unit Testing and Integration Testing?

Unit Testing checks individual components in isolation. Integration Testing checks the interfaces and interactions between components.

Does 100% unit test coverage mean the software has no bugs?

No. Coverage shows which code structure was executed. It does not prove that all requirements, edge cases, or correct results were properly verified.

What is TDD in Unit Testing?

TDD is a development approach that follows the Red-Green-Refactor cycle: first write a failing test, then write enough code to pass it, and finally improve the code while keeping the tests passing.

Why are mocks and stubs used in Unit Testing?

They help isolate the unit from dependencies such as databases, APIs, network services, or other components so that the local behaviour can be tested in a controlled environment.

Conclusion

Unit Testing is the foundation of code-level software testing. Instead of waiting until the entire application is completed, developers test small pieces of software individually and verify their behaviour under normal, boundary, invalid, and exceptional conditions.

A complete Unit Testing approach involves much more than calling a function once. Developers identify test conditions, create controlled fixtures, isolate dependencies, use assertions, apply white-box and black-box test techniques, measure useful coverage, and repeatedly execute the test suite whenever the code changes.

Concepts such as test doubles, stubs, drivers, mocks, dependency injection, Arrange-Act-Assert, code coverage, Test-Driven Development, parameterized testing, and mutation testing make Unit Testing much more powerful in real software development.

Unit Testing = Small Unit + Controlled Input + Expected Result + Assertion

Good Unit Tests = Fast + Independent + Repeatable + Clear + Meaningful

For exams, first remember that Unit Testing tests individual software components in isolation. Then connect it with the complete flow:

Understand Unit → Design Test → Arrange → Act → Assert → Fix → Retest

Once this basic flow is clear, topics such as stubs, drivers, mocks, coverage, TDD, and automation become much easier to understand.

Post a Comment

0 Comments
* Please Don't Spam Here. All the Comments are Reviewed by Admin.
Join Telegram Exam updates and free resources