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:00 PM4:00\,\text{PM} (Week 11 lecture slot).
  • Location: Main lecture hall.
  • Test Composition:
    • 1010 Multiple-Choice Questions (MCQs).
    • 33 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:
    1. Private Constructor: Prevents external direct instantiation using the new keyword.
    2. Static Self-Reference Attribute: Holds the single, static instance of the class.
    3. Public Static getInstance() Method: Provides global access to retrieve or instantiate the single instance.
    4. 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,000100,000 are taxed at 10%10\% (0.100.10) and amounts equal to or exceeding 100,000100,000 are taxed at 15%15\% (0.150.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\text{amount} < 100000, assign taxRate=0.10\text{taxRate} = 0.10; else assign taxRate=0.15\text{taxRate} = 0.15.
    • Invoke legacyPaymentService.calcPayment(taxRate).
  • Android Architecture Example: Android ListView or RecyclerView adapter classes.

Observer Pattern Implementation & Approach Analysis

  • Concrete Observer Implementation Elements:
    1. Implement the Observer interface.
    2. Override the update() interface method to execute custom notification handling.
    3. 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 nn and outputs its square (n2n^2).
    • Execution: User enters n=9n = 9, and system outputs 33.
    • Analysis: A failure occurs because 3≠813 \neq 81. Inspection reveals the code computed n\sqrt{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)(I, O) used to verify whether a given test run passes or fails.
    • Example Pair: Input n=9  ⟹  n = 9 \implies Expected output O=81O = 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:
    1. Specification-Based Oracles: Derived from functional system requirements and documented behavioral requirements.
    2. Model-Based Oracles: Built from abstract behavioral state models.
    3. Human Oracles: Subject-matter experts evaluating system performance.
    4. 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≤121 \le \text{month} \le 12; otherwise returns false.
    • Partitioning into 3 Disjoint Classes:
    1. Smaller / Negative Class: month≤0\text{month} \le 0 (Expected Output: false).
    2. Valid Input Class: 1≤month≤121 \le \text{month} \le 12 (Expected Output: true).
    3. Larger Class: month≥13\text{month} \ge 13 (Expected Output: false).
  • Boundary Value Analysis (BVA):
    • 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\text{month} \le 0): Upper boundary value 00, interior arbitrary negative value −5-5
    • From Class 2 (1≤month≤121 \le \text{month} \le 12): Lower boundary value 11, interior arbitrary valid value 66, upper boundary value 1212
    • From Class 3 (month≥13\text{month} \ge 13): Lower boundary value 1313, interior arbitrary large value 367367

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.