0% found this document useful (0 votes)
16 views57 pages

05 Structural Testing 2025

Structural testing, also known as white-box testing, focuses on verifying the internal structure and code of software rather than its functionality, ensuring all paths and branches are tested. It is essential for detecting hidden errors, improving code quality, and is particularly necessary for safety-critical systems. However, it poses challenges such as high costs, complexity, and the difficulty of achieving complete path coverage due to the exponential growth of potential paths in complex software.

Uploaded by

feathh1
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
16 views57 pages

05 Structural Testing 2025

Structural testing, also known as white-box testing, focuses on verifying the internal structure and code of software rather than its functionality, ensuring all paths and branches are tested. It is essential for detecting hidden errors, improving code quality, and is particularly necessary for safety-critical systems. However, it poses challenges such as high costs, complexity, and the difficulty of achieving complete path coverage due to the exponential growth of potential paths in complex software.

Uploaded by

feathh1
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Structural Testing

Structural Testing
• Structural testing (White-box testing) is a software testing
technique that focuses on verifying the internal structure,
design, and code of the software rather than its functionality.
• It ensures that all paths, statements, and branches are
tested.

• Structural Testing is based on Source Code


• Can Be Dynamic or Static
• Necessary because:
✓ Part of code not fully exercised.
✓ Section of code may be surplus to the requirements.
✓ Errors may be missed by functional requirements.
Approach :Structural Testing
• Understand the Code: Analyze the program’s
internal logic, control flow, and data flow.
• Identify Coverage Criteria: Decide on coverage
measures like statement, branch, condition, path, or
data flow coverage.
• Generate Test Cases: Create test inputs that force
execution through specific parts of the code.
• Execute & Measure: Run the tests and use tools to
measure coverage.
• Iterate: Refine tests to maximize coverage and catch
hidden defects.
Usefulness :Structural Testing

• Detects hidden logical errors missed by black-box


testing.
• Ensures thorough testing of all control paths.
• Helps in identifying unreachable code, dead
paths, redundant conditions.
• Improves code quality, reliability, and
maintainability.
• Useful for security testing, as it exposes
unintended code paths.
• Ensures compliance with coding standards.
The Challenge of Structural Testing

• Requires deep knowledge of the code (specialized


testers/developers).
• Can be time-consuming and costly, especially for large
systems.
• High tool dependency (coverage analyzers, static analyzers).
• May lead to overemphasis on code structure, missing
functional requirements.
• Difficult to achieve 100% path coverage in complex
software (due to exponential path explosion).
• Maintenance of test cases becomes difficult when code
changes frequently.
The Need of Structural Testing
• To ensure all logic and code is tested, not just user-facing
functionality.
• Essential for safety-critical systems (aviation, medical,
banking, defense).
• Helps in early defect detection at the code level.
• Needed when software has complex decision logic.
• Complements black-box testing for higher overall test
coverage.

✓ Structural testing is a needful complement to functional


testing.
✓ It focuses on how software is built internally, ensuring high
code quality.
✓ Though it has challenges like cost, expertise, and
complexity, it is indispensable in critical systems.
Techniques : Structural Testing
Structural testing techniques mainly involve coverage-based
testing:

A. Control Flow Testing


• Statement Coverage – Ensures each statement executes at
least once.
• Branch Coverage – Ensures each decision branch
(True/False) is executed.
• Condition Coverage – Ensures each condition in a decision
takes all possible outcomes.
• Path Coverage – Ensures every independent path in the
code is executed.
Techniques : Structural Testing
B. Data Flow Testing
• Focuses on variable definitions and usage.
• Identifies anomalies like undefined variables, redundant
definitions, improper data use.

C. Loop Testing
• Tests loops with 0 iterations, 1 iteration, multiple iterations,
and boundary values.

D. Slice-based Testing
• Uses program slices (subsets of statements affecting a variable
at a program point) to design test cases.
WHAT IS A GRAPH?
• A graph has a set of nodes and a set of edges that connect
these nodes.
• A graph G = (V, E) consists of a non-empty finite set V of
nodes and a set E of edges containing ordered or
unordered pairs of nodes.
• If an edge ei∈ E is associated with an ordered pair <ni , nj > or an
unordered pair (ni , nj ), where ni, nj∈ V, then the ei is said to connect the
nodes ni and nj.
• The edge ei that connects the node ni and nj is called incident on each
of the nodes.
• The pair of nodes that are connected by an edge are called adjacent
nodes.
• A node, which is not connected to any other node, is called an isolated
node.
• A graph with only isolated nodes is known as null graph
WHAT IS A GRAPH?
• If in graph G = (V, E), each edge ei ∈ E is associated with an ordered pair
of nodes, then graph G is called a directed graph or digraph.
• If each edge is associated with an unordered pair of nodes, then a graph
G is called an undirected graph.

Undirected Graph, the node and edge Directed Graph, the node and edge
sets are given as: sets are given as:
V = (n1, n2, n3, n4, n5, n6 ) V = (n1, n2, n3, n4, n5, n6 )
E = (e1, e2, e3, e4) = ((n1, n2), (n1, n3), E = (e1, e2, e3, e4) = (<n1, n2>, <n1, n3>,
(n2, n4), (n2, n5)) <n2, n4 >, <n2, n5 >)
Types of Graph
If certain pairs of nodes are connected by more than one edge in a
directed or undirected graph, then these edges are known as parallel edges
▪ In Figure, e1 and e2 are parallel
edges connecting nodes n1 and n2.
▪ Similarly, e5 and e6 are also
parallel edges connecting nodes n2
and n5.

If a graph is a directed graph and parallel


edges are in opposite directions, such edges
are considered as distinct edges.
• A directed multigraph may have distinct
parallel edges (like e1 and e2) and
parallel edges (like e5 and e6).
• If numbers or weights are assigned to each
edge of a graph, then such a graph is
called a weighted graph.
Incidence Matrix
Consider a graph G = (V, E) where
V = (n1, n2, n3…..nm)
E = (e1, e2, e3……ek)
In this graph, there are ‘m’ nodes and ‘k’ edges. An incidence matrix is a matrix
with ‘m’ rows and ‘k’ columns whose elements are defined such that:
✓ The sum of entries of any
column of incidence matrix is
always 2.
✓ This is because a column
represents an edge which has
Draw the incidence Matrix of the following Graph only two endpoints.
✓ If, any time, the sum is not
two, then there is some
mistake in the transfer of
information.
✓ If we add entries of a row,
which is corresponding to a
node, we get the degree of
that node.
✓ If all entries of a row are 0’s,
then the corresponding node
is an isolated node.
Problem of Path Explosion in Software Testing
• There are typically many possible paths between the entry and
exit of a typical software program.
Exercise: List various exit path for Exiting Windows OS

It shows how the


system can terminate
in different ways:
Graceful Exit
(Shutdown/Logout)
Forced Exit (Task
Manager Kill)
Crash Exit (System
Failure/BSOD)
Watchdog Exit
(Service Timeout)
Remote Exit
(Scripted/Command)
Problem of Path Explosion in Software Testing
• There are typically many possible paths between the entry and exit of a
typical software program.
• Every decision doubles the number of potential paths,
• every case statement multiplies the number of potential paths by the
number of cases and
• every loop multiplies the number of potential paths by the number of
different iteration values possible for the loop.
• Complete path coverage of even a simple unit is extremely difficult.

The Challenge
Given that testing, like all other development activities has a limited
amount of resources (time, people, equipment),
• the challenge is to select a set of test cases that is most likely to
identify as many different potential defects as possible within those
limits.
• To do this, we must eliminate as much redundancy as possible from
the testing process while still ensuring adequate test coverage.
Path Testing
• Group of Test Techniques
• This type of testing involves:
– Generating a set of paths that will cover every branch in the
program.
– Finding the set of test cases that will execute every path in
this set of program paths.
Steps Involved in Path testing

• Generate flow graph of a program.


• Generate DD path graph.
• Identify independent paths

Given a program written in an imperative programming


language, its Program Graph is a directed graph in which nodes
are statement fragments and edges represent flow of control

If i and j are nodes in the program graph, an edge exists from


node i to node j iff the statement fragment corresponding to node
j can be executed immediately after the statement fragment
corresponding to node i.
Draw Program Graph
Repeat until loop
While loop
Sequence

If then else
CASE Statement
Decision-to-Decision (DD) Paths

In Software Testing (Basis Path Testing / Control Flow Testing)


• DD Path means Decision-to-Decision path i.e. paths of nodes in a
directed graph (path chain).
• It is a sequence of program statements or instructions from one
decision node to another decision node (or to the exit).
• These are used in control flow graphs to identify independent
execution paths for basis path testing.
• Each DD-path corresponds to a set of statements executed
linearly without branching, making them building blocks for
path coverage.

Chain is a path in which the initial and terminal nodes are


distinct, and every interior node has indegree = 1 and
outdegree = 1.
DD-Paths : Definition
A DD-path is a chain in a program graph such that :
Case 1 : it consists of a single node with indeg = 0
Case 2 : it consists of a single node with outdeg = 0
Case 3 : it consists of a single node with indeg  2 or outdeg  2
Case 4 : it consists of a single node with indeg = 1 and outdeg =1
Case 5: it is a maximal chain of length  1

Cases 1 and 2 establish the unique source and sink nodes of the program
graph
Case 3 deals with complex nodes
Case 4 is needed for “short branches”
Case 5 is the “normal case”, in which a DD-path is a single-entry, single-exit
sequence of nodes. The “maximal” part of the case 5 definition is used to
determine the final node of a normal chain
Independent Path
• Independent path is any path through the DD graph that
introduces at least one new set of processing statements or
new condition.
• Use Independent path to ensure that
– Every statement in the program has been executed at least
once.
– Every branch has been exercised for true and false
conditions.
Program Triangle
1. Program triangle2 “Structured Programming version of simpler specification”
2. Dim a,b,c As Integer
3. Dim IsATriangle As Boolean
‘Step 1: Get Input
4. Output (“Enter 3 integers which are sides of a triangle)
5. Input (a,b,c)
6. Output (“side A is”,a)
7. Output (“side B is”,b)
8. Output (“side C is”,c)
‘Step 2: Is A Triangle’
9. If (a<b+c) AND (b<a+c) AND (c<a+b)
10. Then IsATriangle = True
11. Else IsATriangle = False
12. Endif
‘Step 3: Determine Triangle Type’
13. If IsATriangle
14. Then if (a=b) AND (b=c)
15. Then output (“Equilateral”)
16. Else if (a≠b) AND (a≠c) AND (b≠c)
17. Then Output (“Scalene”)
18. Else Output (“Isosceles”)
19. Endif
20. Endif
21. Else Output (“Not a Triangle)
22. Endif
23. End triangle2
Program Graph of the Triangle Program

4 5 6 7 8 Program DD-Path Case of


Graph Nodes Name Definition
4 First 1
9 5-8 A 5
10 11 9 B 3
12 10 C 4
11 D 4
13 12 E 3
21 14 13 F 3
15
14 H 3
16
15 I 4
17 18 16 J 3
19 17 K 4
18 L 4
20 19 M 3
22 20 N 3
21 G 4
23 22 O 3
23 Last 2
DD-Paths for Triangle Program
Program DD-Path Case of
First
Graph Nodes Name Definition
4 First 1 A
5-8 A 5
9 B 3 B
10 C 4 C D
11 D 4 E
12 E 3
13 F 3 F
14 H 3 G H
15 I 4 I J
16 J 3 K L
17 K 4
18 L 4 M
19 M 3 N
20 N 3
21 G 4 O
22 O 3
Last
23 Last 2
Program to find the largest among three numbers`
1. void main()
2. {
3. float A,B,C;
4. clrscr();
5. printf("Enter number 1:\n");
6. scanf("%f", &A);
7. printf("Enter number 2:\n");
8. scanf("%f", &B);
9. printf("Enter number 3:\n");
10. scanf("%f", &C);
/*Check for greatest of three numbers*/
11. if(A>B) {
12. if(A>C) {
13. printf("The largest number is: %f\n",A);
14. }
15. else {
16. printf("The largest number is: %f\n",C);
17. }
18. }
19. else {
20. if(C>B) {
21. printf("The largest number is: %f\n",C);
22. }
23. else {
24. printf("The largest number is: %f\n",B);
25. }
26. }
27. getch();
28. }
Program to find the largest among three numbers`
Exercise 1: Draw DD Path
FindMean (FILE ScoreFile)
{ float SumOfScores = 0.0;
int NumberOfScores = 0;
float Mean=0.0; float Score;
Read(ScoreFile, Score);
while (! EOF(ScoreFile) {
if (Score > 0.0 ) {
SumOfScores = SumOfScores + Score;
NumberOfScores++;
}

Read(ScoreFile, Score);
}
/* Compute the mean and print the result */
if (NumberOfScores > 0) {
Mean = SumOfScores / NumberOfScores;
printf(“ The mean score is %f\n”, Mean);
} else
printf (“No scores found in file\n”);
}
Exercises
Exercise 2: Write a program for the determination of division of a
student. Its input is a triple of positive integers (mark1, mark2,
mark3) and values are from interval [0, 100].
The output may be one of the following words:
• [First division with distinction, First division, Second division,
Third division, Fail, Invalid marks].
Draw the program graph and the DD path graph.

Exercise 3: Write a program for determining the day of the week. Its
input is a triple of day, month and year with the values in the range
1 ≤month≥ 12
1 ≤ day≥ 31
1900 ≤ year ≥ 2058
• The possible values of the output may be [Sunday, Monday,
Tuesday, Wednesday, Thursday, Friday, Saturday, Invalid date].
Draw the program graph and the DD path graph.
Basis Path Testing
• Basis Path Testing is a white-box testing method
proposed by Tom McCabe (1976).
• It uses the control flow graph (CFG) of a program to
design test cases that ensure execution of all linearly
independent paths at least once.

Key Idea
• Represent the program as a control flow graph (CFG)
(nodes = statements, edges = control flow).
• Compute Cyclomatic Complexity (V(G)) to determine the
minimum number of test cases required.
• Design test cases that cover all independent paths in the
graph.
Cyclomatic Complexity
• Cyclomatic complexity is used to find the number of
independent path through a program
• This provides us the upper bound for the number of test that
must be conducted to ensure that all statements have been
executed at least once and every condition have been executed
on its true and false side.
• An independent path is any path through the program that
introduce at least new set of processing statements or a new
conditions.
Cyclomatic Complexity
Complexity is computed in one of three ways.
1. The number of regions of the flow graph correspond to the
Cyclomatic complexity.
2. Cyclomatic complexity, V(G), for a flow graph, G, is defined
as
V(G) = E - N + 2P
Where E is the number of flow graph edges, N is the number
of flow graph nodes and P is number of connected
components.
3. Cyclomatic complexity, V(G), for a flow graph, G, is also
defined as
V(G) = P + 1
where P is the number of predicate nodes contained in the
flow graph G.
Calculate Cyclomatic Complexity for the Given Graph?

• V(G) = No. of
regions of the
graph
• Cyclomatic
Complexity = 4

• V(G) = e - n + 2P • There are three predicate nodes namely


• = 7-5 + 2 node a, node c and node d.
• =4 • Cyclomatic Complexity= No. of
Predicate Statements + 1
• The four independent paths are given as:
1. Path 1 : ace
2. Path 2 : ade
3. Path 3 : adce
4. Path 4 : acbe
Consider Program graph with 3 connected components

• Cyclomatic Complexity Cyclomatic Complexity of each


• V(G)= e-n + 2P' part of the graph independently
• = (4+7+8) - (4+6+7) + 2x3 • V(G - Part I) = 4-4 + 2 = 2
• = (19-17 + 6) = 8 • V(G - Part II) = 7-6 + 2 = 3
• V(G - Part III) = 8-7 + 2 = 3

• In general, the Cyclomatic Complexity of a program graph with P


connected components is equal to the summation of their individual
Cyclomatic Complexities
Essential Complexity
• Part of McCabe’s work on Cyclomatic complexity does more to
improve programming than testing.
• The basic idea is to look for the graph of one of the structured
programming constructs, collapse it into a single node and
repeat until no more structured programming constructs can be
found.

• When a program is well structured (i.e. composed solely of the


structured programming constructs), it can always be reduced
to a graph with one path
Condensing with respect to the structured programming constructs

First
First
A
A
a B
a
C D
E F
G H
F
G H
I b J
I J K L
M
K L
M N
N O
O Last
Last
Condensing with respect to the structured programming constructs

First First

A A

a a

F d F
G c H G c
I b O
N
Last
First
O
e A
Last
a

d
First
Last
e
Cyclomatic Complexity

Cyclomatic Risk Evaluation


Complexity
1-10 a simple program, without
much risk
11-20 more complex, moderate risk

21-50 complex, high risk program

greater than 50 untestable program (very


high risk)
Usage Consideration

Cyclomatic complexity can be applied in several areas,


including
• Code development risk analysis.
– While code is under development, it can be measured for
complexity to assess inherent risk or risk buildup.
• Change risk analysis in maintenance.
– Code complexity tends to increase as it is maintained over
time. By measuring the complexity before and after a
proposed change, this buildup can be monitored and used
to help decide how to minimize the risk of the change.
Usage Consideration

Test Planning.
– Mathematical analysis has shown that Cyclomatic
complexity gives the exact number of tests needed to
test every decision point in a program for each
outcome. Thus, the analysis can be used for test
planning.
– An excessively complex module will require a
prohibitive number of test steps; that number can
be reduced to a practical size by breaking the
module into smaller, less-complex sub-modules.
Graph Matrix
• The graphs are commonly used in testing to find independent paths. Cyclomatic
complexity also gives us the number of independent paths in any graph.
• When the size of the graph increases, it becomes difficult to identify those paths
manually. We may do so with the help of a software tool and graph matrices may
become the basis for designing such a tool
• A graph matrix is a square matrix with one row and one column for every node
of the graph. The size of the matrix (number of rows and number of columns) is the
number of nodes of the graph.

Consider the Graph below and Draw Graph Matrix


Program Graph and Graph Matrix

• Draw Graph Matrix??


Connection Matrix
• Graph matrix is the tabular representation of a program graph. If we assign
weight for every entry in the table, then this may be used for the
identification of independent paths.
• The simplest weight is 1, if there is a connection and 0 if there is no
connection. A matrix with such weights is known as connection matrix.

Each row with more than one entry represents a predicate node and cyclomatic
complexity is Predicate Nodes plus one ( +1).
Practice Exercise
Exercise

1) Draw Graph Matrix


2) Connection Matrix
3) Calculate Cyclomatic
Complexity using Connection
Matrix

DD path graph for classification of triangle problem


Draw Program Flow Chart and DD Path
1 Program Commission (INPUT, OUTPUT)
2 Dim locks, stocks, barrels As Integer
3 Dim locksPrice, stocksPrice, barrelsPrice As Real
4 Dim totallocks, totalstocks, totalbarrels As Integer
5 Dim locksales, stocksales, barrelsales As Real
6 Dim Sales, Commission As Real
7 lockPrice = 45.0
8 stockPrice = 30.0
9 barrelPrice = 25.0
10 totalLocks = 0
11 totalStocks = 0
12 totalBarrels = 0
13 Input (locks)
/*loop condition uses -1
14 while NOT (locks = -1)
to indicate end of data*/
15 Input (Stocks, barrles)
16 total locks = totalLocks + locks
17 totalStocks = total stocks + stocks
18 total barrels = total barrels + barrels
19 Input (locks)
20 End While
21 Output ("lockssold;", totallocks)
program Continued
22 Output ("stockssold:", total stocks)
23 Output ("Barrels sold;", totalBarrels)
24 locksales = lockPrice * total locks
25 stocksales = stockPrice * totalstocks
26 barrelsales = barrelPrice * totalBarrels
27 Sales = locksales + stocksales + barrelSales
28 Output ("total Sales;", Sales)
29 If (sales > 1800.0)
30 Then
31 Commission = 0.10 * 1000.0
32 Commission = Commission + 0.15 * 800.0
33 Commission = Commission + 0.20 *(Sales - 1800.0)
34 Else If (Sales > 1000.0)
35 Then
36 Commission = 0.10 * 1000.0
37 Commission = Commission + 0.15 * (sales - 1000.0)
38 Else Commission = 0.10 * sales
39 Endif
40 Endif
41 Output ("Commission is", Commission
42 End Commission
Program Graph
7 8 9 10 11 12 13

14

15 16 17 18 19

20 21 22 23 24 25 26 27 28

29
30
34
35 38
31
36
32
37
33 39

40
41
42
DD(Decision to Decision) Path Graph
A
DD-Path Nodes
B A 7, 8, 9, 10, 11, 12, 13
B 14
C
C 15, 16, 17, 18, 19
D D 20,21, 22, 23, 24, 25, 26, 27, 28
E 29
E F 30, 31, 32, 33
F G G 34
H 35, 36, 37
H I I 38
J
J 39
K 40
K
L 41, 42
L
Sample Problem

• Draw the flow graph for the given problem?


• Derive the independent paths
• Compute the cyclomatic complexity
• Prepare Test Cases
procedure average
TYPE value [1..100] IS SCALAR ARRAY
TYPE average, total_input, total.valid, minimum maximum, sum IS
SCALAR
TYPE i is INTEGER
i=1;
Total _input = total _valid = 0
Sum = 0
DO WHILE value[ i] <> -999 AND total_input <100
increment total_input by 1;
IF value[ i] >= minimum AND value[ i] <= maximum
THEN increment total_valid by 1;
sum = sum+ value[ i]
ELSE skip endif
increment I by 1;
ENDDO
IF total_valid > 0;
THEN average = sum /total_valid;
ELSE average = -999
ENDIF
procedure average
TYPE value [1..100] IS SCALAR ARRAY
TYPE average, total_input, total.valid, minimum maximum, sum IS SCALAR
TYPE i is INTEGER 1
i=1;
Total _input = total _valid = 0
Sum = 0
DO WHILE value[ i] <> -999 AND total_input <100
2 increment total_input by 1; 3
4 IF value[ i] >= minimum AND value[ i] <= maximum
THEN increment total_valid by 1; 6
5 sum = sum+ value[ i]
ELSE skip endif
7
increment I by 1;
ENDDO
8
IF total_valid > 0;
9
THEN average = sum /total_valid;
ELSE average = -999 10
ENDIF 11
12
13
1. Flow Graph for the Procedure Average

4
10
5

12 11 6

13 7
8

9
Deriving Test Cases

2. Determine the Cyclomatic complexity of the resultant


flow graph.
V(G) = 6 regions
V(G) = 17 edges - 13 nodes + 2 = 6
Deriving Test Cases
3. Determine a basis set of linearly independent paths.
The value of V(G) provides the number of linearly
independent paths through the program control structure. In
the case of procedure average, we expect to specify six paths:
path 1: 1-2-10-11-13
path2: 1-2-10-12-13
path3: 1-2-3-10-11-13
path4: 1-2-3-4-5-8-9-2-….
Path5: 1-2-3-4-5-6-8-9-2-…
path6: 1-2-3-4-5-6-7-8-9-2-...
Deriving Test Cases
3. Determine a basis set of linearly independent paths.
The value of V(G) provides the number of linearly
independent paths through the program control structure. In
the case of procedure average, we expect to specify six paths:
path 1: 1-2-10-11-13
path2: 1-2-10-12-13
path3: 1-2-3-10-11-13
path4: 1-2-3-4-5-8-9-2-….
Path5: 1-2-3-4-5-6-8-9-2-…
path6: 1-2-3-4-5-6-7-8-9-2-...
Deriving Test Cases
Prepare test cases that will force execution of each
path in the basis set.
Data should be chosen so that conditions at the
predicate nodes are appropriately set as each path is
tested. Test cases that satisfy the basis set just
described are
Path 1 test case:
value(k) = valid input, where k<i for 2  i  100
value(i) = -999 where 2  i  100
Expected results: correct average based on k values
and proper totals
Note: Path 1 cannot be tested stand-alone but must be
tested as part of path 4, 5 and 6 tests.
Deriving Test Cases
Path 2 test case:
value(1) = -999
Expected results: Average = -999, other totals at initial
values.
Path 3 test case:
Attempt to process 101 or more values
First 100 values should be valid
Expected results: Same as test case 1.
Path 4 test case:
value(i) = Valid input where i < 100
value (k) < minimum where k < i
Expected results: Correct average based on k values and
proper totals.
Deriving Test Cases
Path 5 test case:
Value(i) = valid input where i < 100
Value(k) > maximum where k <=i
Expected results: Correct average based on n values
and proper totals
Path 6 test case:
Value(i) = Valid input where i < 100
Expected results: Correct average based on n values
and proper totals.

You might also like