Welcome to Testing in Object-Oriented Development!

Welcome! In this chapter, we explore how software developers make sure their code actually works as intended. In Object-Oriented Development, you write classes, instantiate objects, and connect methods together. But what happens if a user types in a negative number, or clicks a button twice? Testing is the safety net that prevents bugs and crashes before real users touch the software.

Don't worry if testing seems like a lot of paperwork at first. Once you understand the standard patterns and classifications, designing test plans becomes one of the most reliable ways to pick up top marks in your CCEA AS 1 exam.

Key Takeaway: Testing is not just about showing that a program works—it is the systematic process of finding defects, checking that requirements are met, and ensuring the program handles both expected and unexpected situations reliably.

---

1. Verification vs. Validation

These two terms sound almost identical, but in software engineering and CCEA mark schemes, they have very specific meanings.

Verification: "Are we building the product right?"

Verification is all about checking the software against the technical specifications, architectural designs, and coding standards. It checks whether the code correctly implements the specified design.

Validation: "Are we building the right product?"

Validation checks whether the finished software meets the actual needs and requirements of the customer or end-user. Even if code is written perfectly without syntax bugs, if it calculates tax using the wrong business rule or solves the wrong problem, it fails validation.

Real-World Analogy: Imagine building a custom bicycle. Checking that the chain fits the gears and the brakes are tightened correctly is verification. Checking whether the customer wanted a mountain bike instead of a road racing bike is validation.

Memory Trick:
Verification = Verifying code against specifications.
Validation = Value to the user.

---

2. Levels and Stages of Testing

In an Object-Oriented application, you do not just test the entire program all at once at the very end. Testing occurs in distinct levels from the smallest piece of code up to the whole system.

Level 1: Unit Testing

Definition: Testing individual methods, functions, or single classes in isolation.
Purpose: To ensure that distinct units of source code operate correctly on their own before being combined with other parts of the system.
Example: Testing a single method called calculateDiscount() inside a Customer class with various inputs to make sure its internal arithmetic is correct.

Level 2: Integration Testing

Definition: Testing the interactions, data transfers, and interfaces between combined components, classes, or modules.
Purpose: Individual classes might work fine on their own, but bugs often emerge when they send data to each other. Integration testing catches these interface faults.
Example: Testing whether the Order class successfully retrieves customer details from the Customer class and passes correct totals to the PaymentProcessor class.

Level 3: System Testing

Definition: Testing the fully integrated, complete software application.
Purpose: To verify that the entire system meets all specified functional requirements (features and calculations) and non-functional requirements (performance, usability, and security).

Level 4: Acceptance Testing (User Acceptance Testing / UAT)

Definition: Testing conducted by the client or end-user.
Purpose: To evaluate whether the system is ready for real-world deployment against the original user requirements.

Alpha vs. Beta Testing

Acceptance and pre-release testing are often broken down into two distinct phases:
Alpha Testing: In-house testing carried out by internal developers and Quality Assurance (QA) teams within a controlled environment before the software is released externally.
Beta Testing: Pre-release testing carried out by an external, independent group of real end-users in their live, everyday operating environments. This uncovers usability issues and latent bugs that internal teams might have missed.

Key Takeaway: Testing moves from small to large: Unit (individual classes/methods) \(\rightarrow\) Integration (connections between classes) \(\rightarrow\) System (the entire program) \(\rightarrow\) Acceptance (client sign-off via Alpha/Beta testing).

---

3. Testing Approaches & Strategies

When you sit down to test code, how do you decide what test cases to run? Developers use two primary testing strategies, as well as manual tracing.

Black-Box (Functional) Testing

Concept: The tester has no knowledge of the internal code structure, logic paths, or implementation details.
How it works: You provide inputs and inspect the outputs based solely on requirements and specifications. It is called "black-box" because the internal workings are hidden from view.
Analogy: Using a vending machine—you press the button and check if the correct drink comes out, without needing to know how the internal wiring operates.

White-Box (Structural / Glass-Box) Testing

Concept: The tester has full access to the source code and its internal architectural design.
How it works: Test cases are designed to execute specific code paths, loops, branch decisions (such as if-else statements), and condition checks.
Analogy: An auto mechanic looking directly inside an open engine while it runs to inspect the pistons, belts, and valves.

Dry Running and Trace Tables

Definition: A manual walkthrough of code using pen and paper without running it on a computer.
How it works: You use a trace table to record variable values step-by-step for each line of execution. This allows you to isolate logic errors and understand algorithm behavior before or alongside machine execution.

Key Takeaway: Black-Box focuses on inputs and outputs without looking at code; White-Box focuses on code paths and internal logic; Dry Running uses manual trace tables to step through code line by line.

---

4. Test Data Classifications (CCEA Standards)

In exam questions, you will frequently be asked to supply test data for validation rules. You must use the official CCEA data classifications. Let's look at an example validation rule: an age field that accepts integer values from \(18\) to \(65\) inclusive (that is, \(18 \le \text{age} \le 65\)).

1. Normal (Typical) Data

Definition: Valid data that falls comfortably within the allowed range and matches the expected data type.
Expected Result: The system accepts and processes the data normally.
Example for \(18 \le \text{age} \le 65\): Input values such as \(25\), \(30\), or \(50\).

2. Extreme (Boundary - Valid) Data

Definition: Valid data at the absolute upper and lower permissible boundaries or limits.
Expected Result: The system accepts and processes the data successfully because it is on the edge of the allowed range.
Example for \(18 \le \text{age} \le 65\): The exact limits: \(18\) and \(65\).

3. Boundary (Invalid) Data

Definition: Data values positioned immediately beyond the upper and lower acceptable boundaries.
Expected Result: The system rejects the data and displays an appropriate error message.
Example for \(18 \le \text{age} \le 65\): The immediate outer values: \(17\) and \(66\).

4. Abnormal / Erroneous / Exceptional Data

Definition: Data that falls completely outside the valid range, or violates the required data type or format.
Expected Result: The system intercepts and rejects the input, preventing a crash and displaying an informative error message.
Examples for \(18 \le \text{age} \le 65\):
- Out-of-range value: \(-5\) or \(120\)
- Data type mismatch: "twenty", "N/A", or "&*%"
- Null / empty input: leaving the field blank.

Quick Summary Table for Range: \(1 \le x \le 100\)
Normal: \(45\) (Valid, typical value)
Extreme (Boundary Valid): \(1\) and \(100\) (Valid, limits of range)
Boundary Invalid: \(0\) and \(101\) (Invalid, immediately outside limits)
Abnormal / Erroneous: \(-50\), \(999\), "abc", blank input (Invalid range or wrong data type)

---

5. Designing a Standard Test Plan

A test plan is a systematic document created before testing begins. When creating a test plan or test table in your exam, use the standard CCEA column layout:

1. Test ID: A unique identifier for the test case (e.g., TC01, T01).
2. Test Objective / Description: The specific property, method, or validation rule being tested (e.g., "Verify error message when age is below 18").
3. Test Data / Input: The exact values or actions entered into the system (e.g., \(17\)).
4. Test Type: The category of data used (Normal, Extreme / Boundary Valid, Boundary Invalid, or Abnormal / Erroneous).
5. Expected Outcome: The precise, calculated output or system response predicted before running the test.
6. Actual Outcome: The observed response when the test is executed.
7. Status / Pass-Fail: A comparison stating whether the actual outcome matched the expected outcome (Pass or Fail).

Worked Example: Test Plan Table

Scenario: A method in a Student class calculates examination grades where marks must be an integer from \(0\) to \(100\) inclusive (\(0 \le \text{mark} \le 100\)), with a pass mark of \(50\).

Test ID: TC01
Objective: Check valid mark produces pass result
Input: \(72\)
Test Type: Normal
Expected Outcome: Result displays "Pass"
Actual Outcome: Result displays "Pass"
Status: Pass

Test ID: TC02
Objective: Check lower extreme boundary value
Input: \(0\)
Test Type: Extreme (Boundary Valid)
Expected Outcome: Result displays "Fail"
Actual Outcome: Result displays "Fail"
Status: Pass

Test ID: TC03
Objective: Check value immediately below minimum allowed mark
Input: \(-1\)
Test Type: Boundary Invalid
Expected Outcome: Error message: "Mark must be between 0 and 100"
Actual Outcome: Error message: "Mark must be between 0 and 100"
Status: Pass

Test ID: TC04
Objective: Check non-numeric text input handling
Input: "Pass"
Test Type: Abnormal / Erroneous
Expected Outcome: Error message: "Invalid input: numerical value required"
Actual Outcome: Error message: "Invalid input: numerical value required"
Status: Pass

Key Takeaway: Always state the exact expected outcome. Never write vague phrases like "it works" or "shows error". State precisely what output or error message should appear!

---

6. Types of Programming Errors

Testing aims to uncover errors. In Object-Oriented programming, errors fall into three main categories:

1. Syntax Errors

What they are: Violations of the grammatical rules of the programming language.
When detected: Detected by the compiler at compile-time.
Result: The program will not build or generate an executable file until fixed.
Examples: Missing semicolons, unmatched curly braces, or misspelling language keywords (e.g., typing whille instead of while).

2. Runtime / Execution Errors

What they are: Errors that occur while the program is executing, causing abnormal program termination (a crash).
When detected: Detected during run-time when an illegal operation is requested.
Common Object-Oriented Examples:
- DivideByZeroException: Attempting to divide a number by zero in an arithmetic expression.
- NullReferenceException: Attempting to call a method or property on an object variable that has not been instantiated (points to null).
- IndexOutOfRangeException: Attempting to access an array or list index that does not exist (e.g., accessing index \(5\) in an array of length \(4\)).

3. Logic Errors

What they are: Flaws in the design, algorithm, or mathematical calculations within the code.
When detected: The program compiles cleanly and runs without crashing, but produces incorrect or unintended output.
Examples: Using > instead of >= in an if statement, or calculating total price as price - discount instead of price * (1 - discount).

---

7. Common Exam Pitfalls to Avoid

Pitfall 1: Vague Expected Outcomes.
Wrong: "Program displays an error."
Right: "Displays error message: 'Age cannot be negative'."

Pitfall 2: Missing Boundary Pairs.
When testing a range like \(1 \le x \le 100\), students often test \(1\) and \(100\), but forget to include the invalid boundary neighbors \(0\) and \(101\). Always test both sides of the boundary line!

Pitfall 3: Confusing Extreme and Abnormal Data.
Remember: Extreme data is valid and must be accepted by the system. Abnormal data is invalid and must be rejected.

Pitfall 4: Forgetting Data Type Errors in Erroneous Testing.
Erroneous data isn't just numbers outside a range. It also includes invalid characters, text in numeric fields, and empty/null inputs.

---

Quick Chapter Review

Verification: Checking code against specifications ("Building it right?").
Validation: Checking software against user needs ("Building the right product?").
Testing Levels: Unit \(\rightarrow\) Integration \(\rightarrow\) System \(\rightarrow\) Acceptance (Alpha/Beta).
Black-Box: Testing inputs and outputs without seeing source code.
White-Box: Testing internal logic, branch conditions, and execution paths using code.
Trace Tables: Dry running code by hand to track variable changes.
Test Data: Normal (typical), Extreme (valid boundaries), Boundary Invalid (immediately outside), Abnormal (out-of-range or wrong type).
Errors: Syntax (compile-time), Runtime (crashes during run), Logic (runs, but produces wrong result).