Testing is the process of executing a program with the intent of finding errors. It validates that software meets requirements and behaves correctly under expected and unexpected conditions.
πΊοΈ Testing Hierarchy
Testing Levels
π¬ Unit Testing
Tests individual modules or functions in isolation. Since the module being tested is not a complete program, helper modules are needed.
Driver Module
A stub that calls the module under test. Used when the module is too low-level to run on its own.
Think of it as a fake "main program" that invokes your function.
Stub Module
A dummy module that replaces a called submodule with a simplified version.
Think of it as a placeholder for modules not yet written.
β¬ Black Box Testing
Tests the system based on inputs and outputs only β the tester has no knowledge of the internal code. Tests are derived from the specification (SRS).
1. Equivalence Class Partitioning (ECP)
Divides the input domain into equivalence classes β groups where all values are expected to behave the same way. Test one value from each class.
ECP Example β Age Input (1β120)
2. Boundary Value Analysis (BVA)
Tests the boundaries between partitions β the edge values are most likely to cause failures. For input range [min, max], test: minβ1, min, min+1, maxβ1, max, max+1
BVA Example β Age Input (1β120)
β¬ White Box Testing
Tests based on knowledge of the internal code structure. The tester knows the source code and designs tests to exercise specific paths, branches, and conditions.
Statement Coverage
Every statement in the code is executed at least once.
Formula: (Statements executed / Total statements) Γ 100%
Branch / Edge Coverage
Every branch (true/false outcome of every decision) is executed at least once.
Stronger than statement coverage. Every edge in CFG traversed.
Condition Coverage
Each individual boolean condition in every decision takes both true and false values.
Path Coverage
Every possible execution path through the program is tested at least once. Strongest but often impractical.
Cyclomatic Complexity
A metric for the number of linearly independent paths through a program's source code. Developed by Thomas McCabe (1976).
Cyclomatic Complexity Formulas
V(G) Value
Risk Level
Recommendation
1 β 10
Low
Simple, well-structured code
11 β 20
Medium
Moderate complexity, manageable
21 β 50
High
Complex, refactoring advised
> 50
Very High
Untestable, must refactor
π§ Integration Testing
Tests combined modules to verify that they work together correctly. Interfaces and interactions between modules are the focus.
Big Bang Approach
All modules are integrated simultaneously and tested as a whole. Simple but very difficult to isolate failures.
Easy to implement
Hard to debug β failure source unclear
Not recommended for large systems
Top-Down Approach
Start with the top-level module and progressively integrate lower-level modules. Uses stubs for not-yet-integrated modules.
Early testing of main control flow
Needs stub modules
Useful when top-level logic is complex
Bottom-Up Approach
Start from lowest-level modules and build up. Uses driver modules to call the lower-level modules being tested.
No stubs needed
Needs driver modules
Good when low-level modules are critical
Mixed / Sandwich Approach
Combines top-down and bottom-up. Top levels tested top-down, lower levels tested bottom-up simultaneously. Most practical for large systems.
βοΈ Verification & Validation (V&V)
Verification
"Are we building the product right?"
Checks that the software is built according to its specification. Static activity β no need to run the code.
Reviews, walkthroughs, inspections
Formal verification
Static analysis tools
Validation
"Are we building the right product?"
Checks that the software meets the actual user needs and requirements. Dynamic activity β requires execution.
Black box testing
User acceptance testing (UAT)
Alpha and beta testing
Memory tip: Verification = Specification check. Validation = Customer need check. Both are needed for a quality product.