Software Engineering: Design Patterns Revision and Software Testing Guide
Test 2 Structure, Logistics, and Revision Scope
Test Format: Written examination similar in structure to Test 1.
Date & Time: Thursday, October 8 at 4:00PM (Week 11 lecture slot).
Location: Main lecture hall.
Test Composition:
10 Multiple-Choice Questions (MCQs).
3 Short Answer / Long Code Writing Questions.
Syllabus Coverage:
Design pattern content delivered across Week 6, Week 7, and Week 9.
The long answer / short answer questions specifically target four key design patterns: Singleton, Adapter, Observer, and Factory patterns.
Android-specific features and newly introduced software testing concepts form part of the multiple-choice section.
Design Patterns Revision & Selected Practice Problems
Anti-Patterns:
God Class / Blob Anti-Pattern: Refers to a class that has grown overly large or acts as a centralized repository gathering multiple methods and responsibilities that do not belong anywhere else.
Singleton Pattern Initialization Schemes:
Eager Initialization: Creating the singleton instance at the time of class loading or within the class constructor, ensuring it is immediately instantiated and available.
Lazy Initialization: Delaying the creation of the singleton instance until the point where it is first explicitly requested or accessed by a call to getInstance().
Factory Pattern Intent:
Defines a standard interface for object creation while deferring the precise instantiation logic to subclasses.
Adapter Design Pattern Intent:
Connects two incompatible or unrelated interfaces so they can collaborate and work together directly without altering their underlying source code.
Singleton Pattern Categorization:
Classified under Creational Design Patterns, as it controls and restricts object instantiation to a single shared instance.
Pattern Implementations in Android:
The Android ListView class simultaneously incorporates the Adapter Pattern (to bridge underlying data collections to visual views) and the Observer Pattern (to listen for dynamic data updates).
Short Answer Revision: Design Pattern Implementation
Singleton Pattern Requirements & Output Trace
Core Components of a Concrete Singleton Class:
Private Constructor: Prevents external direct instantiation using the new keyword.
Static Self-Reference Attribute: Holds the single, static instance of the class.
Public Static getInstance() Method: Provides global access to retrieve or instantiate the single instance.
Encapsulated State Attributes: Internal fields (e.g., score or value) manipulated through getters and setters.
Output Evaluation Scenario:
If two reference variables (ref1 and ref2) retrieve the instance via getInstance() and ref1.setValue(20) is executed:
Printing the values from both references yields 20 and 20 because both reference variables point to the exact same memory instance.
Real-World Applications of Singleton:
Global Leaderboard state management.
Application-wide Logging services (Logger).
Global Configuration or Connection Managers.
Adapter Pattern Implementation Logic
Problem Scenario:
Legacy class LegacyPaymentService exposes calcPayment(double tax).
Modern interface PaymentProcessor requires dynamic tax calculation where transaction amounts under 100,000 are taxed at 10% (0.10) and amounts equal to or exceeding 100,000 are taxed at 15% (0.15).
Adapter Implementation Requirements:
Create an adapter class PaymentAdapter that implements PaymentProcessor.
Maintain an internal instance reference to LegacyPaymentService.
Override the primary execution method (e.g., pay(double amount)):
Perform conditional check: if amount<100000, assign taxRate=0.10; else assign taxRate=0.15.
Invoke legacyPaymentService.calcPayment(taxRate).
Android Architecture Example: Android ListView or RecyclerView adapter classes.
Override the update() interface method to execute custom notification handling.
Define a constructor accepting identifying information (e.g., a String observer name).
Push vs. Pull Architecture:
Push Model: The Subject actively passes state updates directly into the parameters of the observer's update() method upon state change.
Pull Model: The Subject merely notifies the Observer of a change, and the Observer subsequently queries or pulls the specific updated state back from the Subject.
An implementation where data parameters are directly dispatched to observers during notifyObservers() constitutes a Push approach.
Fundamentals of Software Testing & Terminology
Dijkstra's Maxim on Testing:
"Testing can show the presence of bugs, but not their absence."
Test suites can confirm that specific tested conditions fail or work, but no finite set of tests can guarantee that a software system is completely free of bugs.
Definition of Software Testing:
The deliberate process of executing a program with the intentional goal of uncovering defects and causing system failures.
Core Terminology:
Failure: An unacceptable, incorrect behavior or output exhibited by a system at runtime (e.g., an incorrect calculation result or a system crash).
Defect (Bug): A physical flaw or logic error in any system artifact (requirements, architecture, design, or source code) that induces a failure.
Error: A human mistake, slip-up, or incorrect design choice made by a developer during development that introduces a defect into the system.
Illustrative Fault Trace Case Study:
Requirement: System prompts for an integer n and outputs its square (n2).
Execution: User enters n=9, and system outputs 3.
Analysis: A failure occurs because 3=81. Inspection reveals the code computed n without throwing any runtime syntax or execution errors. The root cause is a developer error leading to a defect in requirement comprehension rather than a programmatic syntax syntax error.
Efficiency Goal in Testing:
Software strategies must aim to maximize defect discovery using the minimum number of redundant test cases, preserving execution speed and maintenance bandwidth.
Software Testing Strategies & Best Practices
Scope of Responsibility:
Developers must focus test suites strictly on code for which they are directly responsible.
Standard language libraries (e.g., standard Java Math packages) and well-maintained third-party dependencies should not be re-tested locally.
Testing Timing Strategies:
Test-Driven Development (TDD): Writing automated tests prior to writing actual functional code.
Beta Testing: Releasing early builds to real users to evaluate operation under actual usage conditions.
Execution Methodologies:
Automated Testing: Preferred for speed, consistency, repeatability, and eliminating human oversight.
Manual Testing: Highly effective for user experience, graphical layout alignment, and qualitative human-centric interfaces.
Debugging vs. Software Testing:
Debugging is the process of locating, analyzing, and fixing known faults during coding.
Testing is the systematic execution designed to reveal previously unknown failures.
The Golden Rule of Software Testing:
Programmers should not test their own code. - Rationale: Developer bias creates cognitive blind spots. Authors naturally re-evaluate their code using the exact same mental models and implicit assumptions used when writing it, masking subtle syntax or edge-case logic flaws. Independent testing teams or mandatory cool-off periods yield objective evaluation.
Black-Box vs. White-Box Testing & Test Oracles
Black-Box Testing:
System evaluation based exclusively on inputs and observed outputs without visibility into internal implementation structures or code syntax.
White-Box Testing:
System evaluation conducted with full access to internal source code, architecture, design specifications, and control paths.
Test Oracles:
A defined input-output benchmark pair (I,O) used to verify whether a given test run passes or fails.
Example Pair: Input n=9⟹ Expected output O=81.
Categories of Test Oracles:
Implicit Oracles: Baseline software expectations assumed across all systems (e.g., the software must not crash or cause memory leaks regardless of input). Implicit oracles are subject to false positives.
Explicit Oracles: Formally constructed, explicit expected outcome sets derived for specific functions.
Methods for Selecting Test Oracles:
Specification-Based Oracles: Derived from functional system requirements and documented behavioral requirements.
Model-Based Oracles: Built from abstract behavioral state models.
Human Oracles: Subject-matter experts evaluating system performance.
Golden Standard (Master) Oracles: Utilizing an existing, highly trusted legacy system execution build as the evaluation baseline when formal specification docs are unavailable.
Equivalence Partitioning & Boundary Value Analysis
Equivalence Partitioning (Equivalence Classes):
A technique that divides the infinite set of possible system inputs into distinct, disjoint groups (classes) where all members of a group are assumed to be processed identically by the program.
Reduces testing redundancy by requiring only one representative test case per equivalence class.
Weak Equivalence Class / Single Fault Testing: Evaluates system behavior by varying one equivalence class variable at a time under the assumption that faults occur independently.
Equivalence Class Case Study: validMonth(int month):
Function returns true if 1≤month≤12; otherwise returns false.
Complements equivalence partitioning by targeting input values directly at the upper and lower boundaries of each class, where software faults statistically concentrate.
Optimal 7-Point Test Oracle Suite for validMonth:
From Class 1 (month≤0): Upper boundary value 0, interior arbitrary negative value −5
From Class 2 (1≤month≤12): Lower boundary value 1, interior arbitrary valid value 6, upper boundary value 12
From Class 3 (month≥13): Lower boundary value 13, interior arbitrary large value 367
Android Unit Testing Principles
Unit Testing Scope:
Focuses on testing the smallest, isolated units of functional source code (individual methods and classes).
Principle of Independence:
Unit tests must be completely modular, independent, and self-contained.
No test execution or outcome may depend on the state, side effects, or execution order of another test case.