NivaarExam PrepOfficial exam papers ↗

25-Comp-A6 Software Engineering · May 2016

Question 4 of 8: Software testing

Nivaar worked solution (AI-drafted; not reviewed by a licensed engineer)

Notes on this paper

Paper: 98-Comp-A6, Software Engineering — 2016-May, 3 hours, closed book, no calculators. Answer any five of the eight questions; all five count equally (20 marks each, 100 total). All eight questions are answered below.

Reference texts: Sommerville, Software Engineering (10th ed., Pearson) — software process models, object-oriented and function-oriented design, real-time systems, software testing, formal methods, rapid software development, client-server/distributed architectures; Pressman, Software Engineering: A Practitioner's Approach (9th ed.) — supplementary process/testing coverage; IEEE/ISO 12207 — software life-cycle processes; SWEBOK — body-of-knowledge cross-reference.

Question 4: Software testing (a) 5, (b) 5, (c) 10 — 20 marks

Question text not reproduced: the examination questions are © Engineers and Geoscientists BC. Open the official past paper (linked at the top of this page) to read the question, then follow the worked solution below.

(a) Functional vs. Structural Testing

Functional (black-box) testing derives test cases purely from the specification, without reference to the program's internal structure: the tester picks inputs (typically using equivalence partitioning and boundary-value analysis) that exercise the documented behaviour and checks the outputs against expected results. Structural (white-box) testing derives test cases from the program's internal structure — its control-flow graph — aiming to exercise specific code elements (statements, branches, or paths) that a black-box test suite might never reach, since it is derived without knowledge of which inputs actually traverse which code paths.

The two are complementary rather than substitutes: functional testing confirms the system does what the specification says it should, but says nothing about code paths the specification never anticipated (an unhandled error branch, say); structural testing can guarantee a coverage criterion (e.g. every branch executed at least once) but a path being executed and producing the correct result are different things — structural testing alone cannot tell you what the correct result should be. The standard defect-testing process therefore uses functional testing first to derive a specification-based test suite, then measures the structural coverage that suite achieves and adds further, structurally-motivated test cases to exercise any statements or branches the functional suite missed (a common target is 100% branch coverage for safety- or business-critical code).

(b) Testing Detects Presence, Not Absence, of Errors

A test run exercises the program on one specific input (or a small finite set of inputs) and observes whether the output matches what was expected; if it does not, an error has been demonstrably found. But the space of possible inputs to any non-trivial program is astronomically large or infinite, and exhaustively trying every one is not feasible in any practical amount of time. A test suite can therefore only ever sample that space. Passing every test in the suite proves that the program behaves correctly on the particular inputs tried — it says nothing about the vastly larger set of inputs that were never tried, any one of which could still trigger a latent defect. This is Dijkstra's well-known observation: testing can conclusively show a bug exists (by triggering it) but can never conclusively show that no bug exists, because "no bug found yet" and "no bug present" are not the same statement given an untested remainder of the input space.

(c) Testing Strategy for the Residential Home Security System

Question 3's design has four sensor subclasses feeding one coordinating BaseStation, which drives a local AlarmSounder and a remote, network-dependent CentralMonitoringLink — that structure drives a four-level strategy escalating from isolated unit tests to full system scenarios:

LevelTargetTechniqueExample
UnitEach Sensor subclass, BaseStation's arm/disarm/toggle logicStructural (branch coverage) with stubbed sensor inputWaterSensor.checkState() correctly reports triggered/not-triggered for readings above/at/below its conductivity threshold
IntegrationSensor → BaseStation → AlarmSounder / CentralMonitoringLink chainsFunctional, equivalence-partitioned by sensor type and armed statea SmokeSensor trigger reaches AlarmSounder and CentralMonitoringLink even while the system is disarmed; a MotionDetector trigger while disarmed reaches neither
SystemWhole security system against realistic scenariosScenario/use-case based, black-boxarm system, open a door, disarm within the entry delay (no alarm); arm, trigger a disabled motion detector (no alarm, per the per-sensor toggle)
Non-functionalNetwork reliability, concurrency, timingFault-injection / stress testssimulate the Internet link failing exactly as an alarm condition occurs; two sensors (e.g. a window and a motion detector) triggering within the same polling cycle

Because the system protects both life-safety (smoke, water/flood) and security (intrusion) conditions, structural coverage is weighted more heavily than a purely business system would need — every branch of BaseStation.onSensorTriggered() should be exercised, including the always-active life-safety path that bypasses the armed/disarmed check, and the CentralMonitoringLink failure path (network unreachable during a genuine alarm), which a purely scenario-driven functional suite is easy to under-test since it requires deliberately injecting a fault rather than exercising a "happy path" scenario. Regression testing after any sensor add/remove or zone reconfiguration is also required, since BaseStation's sensor set is owner-configurable at runtime rather than fixed at build time.