19-Soft-A6 Software Quality Assurance · December 2013
Nivaar worked solution (AI-drafted; not reviewed by a licensed engineer)
National Exams, December 2013 — 04-Soft-A6, Software Quality Assurance (open book, non-communicating calculator permitted, 3 hours). Per the paper's own notes, FIVE of the EIGHT questions constitute a complete exam and each is of equal value; all eight are answered in full below as a complete study resource.
Reference texts. Pressman, Software Engineering: A Practitioner's Approach, 9th ed., Ch. 15 (SQA), Ch. 17–18 (unit/integration/validation/system testing strategy), Ch. 19–20 (white-box basis-path testing, black-box equivalence partitioning & boundary value analysis); Sommerville, Software Engineering, 10th ed., Ch. 8 (Software Testing) and Ch. 24 (Quality Management); SWEBOK v4, Software Quality KA and Software Testing KA; ISO/IEC 25010 (SQuaRE) for the software product quality model referenced in Question 1; ISO/IEC/IEEE 12207 (Software life cycle processes) for the process-standard referenced in Question 1(b).
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.
Appendix A (as printed in the exam) is reproduced below for reference:
// A simple in-memory property database program. Through a menu, the user
// decides if he or she wants to see a property database on the screen or
// search for a specific property.
#include <iostream.h>
#include <string.h> // For strcmp()
void DisplayMenu();
int GetAnswer();
void DisplayProps(char * code[], float price[], char * addr[], float commPer[]);
void SearchProps (char * code[], float price[], char * addr[], float commPer[]);
int const NUM = 8; // Eight properties maximum
void main()
{
int ans;
char * code[NUM] = { "231DV", "821WQ", "199OI", "294JU",
"901RE", "829BN", "483LQ", "778AS" };
float price[NUM] = { 89432.34, 123029.34, 321293.95, 214293.20,
68402.92, 421034.53, 232456.54, 432123.40 };
char * addr[NUM] = { "919 N. Elm", "2202 West Sycamore", "7560 E. 26th Pl.",
"213 W. 104th Ave", "123 Willow Rd.", "5629 S. 188th",
"45 North Harvard", "17093 Lansford" };
float commPer[NUM] = { .072, .07, .065, .091, .078, .0564, .102, .0834 };
do
{
DisplayMenu();
ans = GetAnswer();
switch (ans)
{
case (1): { DisplayProps(code, price, addr, commPer); break; }
case (2): { SearchProps (code, price, addr, commPer); break; }
case (3): { return; break; } // "unreachable code"
} // If user entered bad value, while loop will repeat
} while (ans != 3);
return;
}
//--------------------------------------------------------------------------
void DisplayMenu() { /* prints the 3-choice menu; no branch */ }
//--------------------------------------------------------------------------
int GetAnswer() { int ans; cin >> ans; cin.ignore(80,'\n'); return (ans); }
//--------------------------------------------------------------------------
void DisplayProps(char * code[], float price[], char * addr[], float commPer[])
{
int ctr;
cout.precision(2); cout.setf(ios::showpoint); cout.setf(ios::fixed);
for (ctr = 0; ctr < NUM; ctr++)
{
cout << "Code: " << code[ctr] << "\t Price: $" << price[ctr] << endl;
cout << "Address: " << addr[ctr] << endl;
cout << "Commission percentage: " << commPer[ctr]*100.0 << "%" << endl << endl;
if (ctr == 3) // Don't scroll off too fast
{
cout << "Press enter to continue..."; cin.ignore(80,'\n');
}
}
cout << "Press enter to continue..."; cin.ignore(80,'\n');
return;
}
//--------------------------------------------------------------------------
void SearchProps(char * code[], float price[], char * addr[], float commPer[])
{
int ctr; int found = 0; char buf[6];
cout << "What is the property's code? "; cin.getline(buf, 6);
for (ctr = 0; ctr < NUM; ctr++)
{
if (!strcmp(code[ctr], buf))
{
cout << "Code: " << code[ctr] << "\t Price: $" << price[ctr] << endl;
cout << "Address: " << addr[ctr] << endl;
cout << "Commission percentage: " << commPer[ctr]*100.0 << "%" << endl << endl;
found = 1;
break;
}
}
if (!found) { cout << "* I'm sorry, but I don't find code " << buf; }
return;
}
Find. The control-flow graph, cyclomatic complexity V(G), and a basis (minimum, independent) set of test cases for each unit in Appendix A, ordered by the program's call hierarchy as the hint directs.
main() last, once real (already-tested) units are available to replace what would otherwise need stubs.DisplayMenu() and GetAnswer() are leaves with no decision logic (V(G) = 1 each) — a single driver call each is sufficient, since with only one path there is nothing further to distinguish. DisplayProps() and SearchProps() are also leaves (they call only library I/O) but contain real decision logic, so each needs its own basis-path test set, built with a driver, before main() is tested. main() is tested last, calling the four real, already-verified units directly (bottom-up integration, Question 3(b)) rather than stubs.DisplayProps(): 1 start → 2 for-test → 3 loop body(print) → 4 if(ctr==3) → 5 if-true(pause) → 6 merge/increment → 7 exit, with edges {1-2, 2-3, 2-7, 3-4, 4-5, 4-6, 5-6, 6-2}: N=7, E=8, $V(G) = 8-7+2 = 3$. SearchProps(): 1 start → 2 for-test → 3 if(!strcmp) → 4 match/break → 5 no-match/increment → 6 if(!found) → 7 not-found body → 8 exit, with edges {1-2, 2-3, 2-6, 3-4, 3-5, 5-2, 4-6, 6-7, 6-8, 7-8}: N=8, E=10, $V(G) = 10-8+2 = 4$ (shown in Fig. Q6-2).main()'s flow graph, including the un-defaulted switch's implicit branch. Nodes: 1 start/declarations → 2 DisplayMenu() call → 3 GetAnswer() call → 4 switch(ans) → 5 case 1/DisplayProps → 6 case 2/SearchProps → 7 case 3/return → 8 merge → 9 while(ans!=3) test → 10 exit. The switch has no default, so its own comment ("If user entered bad value, while loop will repeat") describes a real fourth edge, $4\to 8$, taken whenever ans matches none of 1/2/3 and execution falls through the switch untouched. Edges: {1-2, 2-3, 3-4, 4-5, 4-6, 4-7, 4-8, 5-8, 6-8, 7-10, 8-9, 9-2, 9-10}: N=10, E=13, $V(G) = 13-10+2 = 5$.main(): switch (4-way, contributes 3) + while-test (2-way, contributes 1) $= 1+3+1=5$ — matches. SearchProps(): three 2-way decisions (for-test, strcmp-test, found-test) $=1+1+1+1=4$ — matches. DisplayProps(): two 2-way decisions $=1+1+1=3$ — matches. Both formulas agree for every unit, which is the standard cross-check basis path testing uses before trusting a hand-drawn graph.SearchProps(). Predicate (decision) nodes 2, 3, and 6 are outlined in blue; each contributes one independent path beyond the baseline.| Unit | V(G) | Basis test-case set (V(G) cases, collectively covering every edge) |
|---|---|---|
DisplayMenu() | 1 | Single call — confirm the 3-choice menu text prints once; no branch to isolate. |
GetAnswer() | 1 | Single call with any integer input — confirm the same value is echoed back by the driver; no branch to isolate. |
DisplayProps() | 3 | (1) Normal pass: all 8 records print, output pauses exactly once at ctr==3 — exercises the loop's T edge and the if's T edge. (2) Force NUM = 0 in the driver's stub array: loop body never runs — exercises the loop's F edge directly (else the loop always executes at least once with the real NUM = 8). (3) Force the pause index out of range (e.g. a driver-supplied array where no ctr ever equals 3, by using NUM ≤ 3): confirms the if's F edge on every iteration with no pause — a genuine defect this catches is a hard-coded pause index (3) that silently stops pausing at all if the property count ever drops to 3 or fewer. |
SearchProps() | 4 | (1) Code found on the FIRST comparison (buf = "231DV"): shortest path, exercises the break-out edge directly. (2) Code NOT found anywhere (buf = "ZZZZZ"): loop runs all 8 iterations to natural exhaustion, exercises the loop's own F edge and the "not found" message. (3) Code found in the MIDDLE (buf = "901RE", index 4): confirms the strcmp test's F edge is taken (and re-entered) at least once before its T edge fires — distinct from cases (1)/(2)'s degenerate zero/eight repeats. (4) Code found on the LAST element (buf = "778AS", index 7 = NUM−1): the boundary case most likely to expose an off-by-one in ctr<NUM vs. ctr<=NUM. |
main() | 5 | (1) ans = 1 then 3 ("view", quit): exercises case 1 and the loop-back edge. (2) ans = 2 then 3 ("search", quit): exercises case 2. (3) ans = 3 immediately: exercises case 3's direct-return edge, the shortest possible path. (4) ans = 9 (out of range) then 3: exercises the un-defaulted switch's implicit fall-through edge $4\to 8$, i.e. checks the "bad value, loop will repeat" comment is actually true rather than a stale assumption. (5) ans = 1, 1, then 3 (repeat the same valid choice twice before quitting): confirms the loop-back edge is safely repeatable, not just single-shot — the kind of multi-iteration check that basis path testing alone does not guarantee and Question 4(a)'s separate loop-testing technique specifically targets. |