Software is built in layers: small units of code are combined into modules, modules are combined into a complete system, and the complete system is finally handed over to users. Testing follows the same structure. The levels of testing describe who tests what, at which stage, and with what goal. Each level catches a different kind of defect, so skipping one usually means those defects leak into the next level, where they are more expensive to fix.
| Level | What is tested | Who usually performs it | Main goal |
|---|---|---|---|
| Unit testing | Individual functions, methods or classes | Developers | Verify each unit of code works in isolation |
| Integration testing | Interfaces and data flow between modules | Developers and testers | Find defects in how components interact |
| System testing | The complete, integrated application | Independent testing team | Verify the system against requirements end to end |
| Acceptance testing | The system in a business context | Clients, business users, end users | Confirm the system is ready for real use |
Unit Testing
A unit is the smallest testable piece of code, such as a function that calculates GST on an order amount. Developers write unit tests, usually automated with frameworks like JUnit, TestNG, pytest or Jest, to confirm that the function returns the correct output for various inputs. Unit testing is a form of white box testing because the developer knows the internal code.
Benefits include early defect detection, safer refactoring and faster debugging. As a manual tester you rarely write unit tests, but you should know they exist and ask about unit test coverage when a module is unusually buggy.
Integration Testing
Modules that work perfectly on their own can still fail when combined. Data may be passed in the wrong format, an API may return an unexpected field, or a timeout may not be handled. Integration testing focuses on these interfaces.
Consider an e-commerce app with modules Login, Product Search, Cart, Payment and Order History. Integration tests check things like: does the Cart receive the correct product price from Search, and does Order History show the order after Payment confirms it?
Integration approaches
| Approach | How it works | Advantages | Disadvantages |
|---|---|---|---|
| Big bang | All modules are combined at once and tested together | Simple; suitable for small systems | Hard to locate the source of a defect; testing starts late |
| Top-down | Testing starts from top-level modules (for example, the UI) and moves downward; missing lower modules are replaced by stubs | Major control flow and design flaws found early; early working prototype | Lower-level modules are tested late; many stubs needed |
| Bottom-up | Testing starts from the lowest modules (for example, the payment calculation) and moves upward; missing higher modules are replaced by drivers | Core logic tested thoroughly and early | No working prototype until late; UI flow issues found late |
| Sandwich (hybrid) | Combines top-down and bottom-up, meeting in a middle layer | Parallel testing; balances the benefits of both | More complex and costly to plan |
Stubs and drivers
| Stub | Driver |
|---|---|
| A dummy program that replaces a called (lower-level) module | A dummy program that replaces a calling (higher-level) module |
| Used in top-down integration | Used in bottom-up integration |
| Example: a fake Payment module that always returns "success" so the Cart flow can be tested | Example: a simple script that calls the GST calculation module with test amounts because the Cart screen is not ready |
A stub is called by the module under test, so it sits below. A driver drives (calls) the module under test, so it sits above.
System Testing
System testing evaluates the complete, integrated application against the functional and non-functional requirements. It is usually performed by an independent testing team in an environment that closely resembles production. This is where most manual testers spend the majority of their time.
System testing is mostly black box testing, focused on behaviour rather than code. It includes end-to-end flows, for example: search for a train, select seats, add passengers, pay through UPI, receive the e-ticket by SMS and email, and see the booking in "My Trips". It also covers non-functional areas such as performance, security, usability and compatibility.
Acceptance Testing (UAT)
User Acceptance Testing confirms that the system satisfies business needs and is ready for deployment. It is performed by the client, business users or end users, often using real-world scenarios. A successful UAT usually leads to formal sign-off for release.
Alpha vs beta testing
| Aspect | Alpha testing | Beta testing |
|---|---|---|
| Performed by | Internal users, employees or in-house testers acting as users | A limited group of real external users |
| Location | At the developer's site, in a controlled environment | At the users' own locations, in real conditions |
| Timing | Before beta, near the end of development | After alpha, just before full release |
| Example | Staff of a fintech company use a new wallet feature for two weeks | 5,000 selected customers receive an early version of the app through a beta programme |
Other forms of acceptance testing include contract acceptance testing (checking criteria agreed in a contract), regulatory acceptance testing (for example, compliance with banking regulations) and operational acceptance testing (backup, recovery and maintenance readiness).
For a "Split bill" feature in a payment app: the developer unit tests the function that divides ₹1,000 among three people; integration testing checks that the split amounts are sent correctly to the payment request module; system testing validates the complete flow on multiple devices; and UAT lets business users confirm that the feature matches how real friends split bills.
Do not confuse testing levels (where in the life cycle) with testing types (what quality attribute). For example, performance testing is a type that can be done at the system level. Types are covered in the next lesson.