# An Empirical Study on Failed Error Propagation in Java Programs with Real
Faults

Gunel Jahangirova
Università della Svizzera italiana
Lugano, Switzerland
&David Clark
University College London
London, UK
&Mark Harman
Facebook & University College London
London, UK
&Paolo Tonella
Università della Svizzera italiana
Lugano, Switzerland

###### Abstract

During testing, developers can place oracles externally or internally with
respect to a method. Given a faulty execution state, i.e., one that differs
from the expected one, an oracle might be unable to expose the fault if it is
placed at a program point with no access to the incorrect program state or
where the program state is no longer corrupted. In such a case, the oracle is
subject to failed error propagation.

We conducted an empirical study to measure failed error propagation on
Defects4J, the reference benchmark for Java programs with real faults,
considering all 6 projects available (386 real bugs and 459 fixed methods).
Our results indicate that the prevalence of failed error propagation is
negligible when testing is performed at the unit level. However, when system-
level inputs are provided, the prevalence of failed error propagation
increases substantially. This indicates that it is enough for method
postconditions to predicate only on the externally observable state/data and
that intermediate steps should be checked when testing at system level.

##  1 Introduction

Software faults are difficult to detect and fault removal consumes a
significant proportion of software development and evolution [6, 8]. One of
the widely-attributed sources of such difficulty is the possibility of failed
error propagation (FEP): a fault may corrupt the program’s internal state, yet
this corruption fails to propagate to any point at which it is observed [13,
34, 45]. Such non-propagating faults play the role of ‘nasty unexploded
mines’; lurking undetected in software systems, waiting for that slight change
in execution environment that allows the corrupted error state to propagate,
causing unexpected system failure.

Despite the importance of FEP, surprisingly few empirical studies in the
literature assess the extent of the problem. Empirical evidence based on a few
examples of real faults is available only for the C/C++ programming language
[7, 10, 15, 11], while for Java results have been obtained only with mutants
[30, 48], not with real faults. In the absence of robust empirical analysis,
the research and practitioner community is left with suspicions of a silent
menace of unknown proportions.

In order to bridge the gap between suspicions and empirical evidence we set
out to perform a large empirical study of FEP on real faults from Defects4J
[20], a large scale benchmark that has become the de-facto standard [21, 26,
4, 25, 27, 47, 33, 49, 37] for real faults in Java programs. Our study
encompasses all six projects in Defects4J and the associated 386 real faults.
Since FEP is a statistical property of a method (in fact, it may occur in some
executions and not in others), we faced the problem of obtaining a sample of
empirical data that is large enough to draw statistically meaningful
conclusions. This requires that the considered faults are executed multiple
times, in program executions that differ from each other, and that the effects
of the faults on the program state are observed along corresponding execution
points of both faulty and fixed program. We have extended the EvoSuite [12]
test case generator to address the first problem and we have developed our own
trace alignment algorithm to address the second problem.

Our study revealed a very surprising finding: in this significant corpus of
real world bugs, the prevalence of unit-level FEP is negligible. We further
experimented with seeded synthetic faults (mutants [17]), for which we
observed that unit-level FEP was found to be much more prevalent. To further
analyse the propagation of real faults we conducted experiments testing
programs at the system level rather than on unit level. Our results show that
the rate of system-level FEP with real faults is substantially higher than the
rate of unit-level FEP both with real and synthetic faults.

##  2 Failed Error Propagation

The effectiveness of testing depends on the use of oracles that are sensitive
to any deviation from the intended program behavior and that report all such
deviations as test failures. One of the key decisions about the use of oracles
is their placement. Oracles can be placed in test cases in the form of a test
case assertion, i.e., outside the method under test (unit level testing) or at
the end of the entire system execution (system level testing); at the end of
the execution of the method under test, before the return point (acting as a
post-condition); or even internally, at any arbitrary execution point,
predicating on the intermediate program states observed during method
execution.

An external/output oracle (i.e., a test case oracle) has limited capability to
discriminate between incorrect and correct method executions, since it can
only check the value returned by the method under test and the externally
observable state affected by the method under test (e.g., global variables,
externally observable object states, persistent changes in the environment,
output produced by the whole system execution). In a specific program
execution, an error may escape detection by an external/output oracle if it
generates an internal state that differs from the expected one without
producing any externally visible effect. This means it returns the expected
value and it changes the externally visible state in the expected way. Of
course, in order for this to be an error, there must be at least one execution
where the error produces an externally visible incorrect effect. Hence,
external/output oracles can eventually detect all faults, but they might
require a lot of test cases if there is only a low probability that the
internal state differences propagate to externally visible differences. When
this happens at the unit level, we say the method is subject to external
failed error propagation (extFEP). When this happens at the system level, we
say the method is subject to system failed error propagation (sysFEP).
External/output oracles are weak in comparison with return point or internal
oracles when external/system FEP happens.

At the unit level a return point oracle (i.e., an internal oracle placed right
before the return point) is more powerful than an external oracle because it
can predicate on the entire execution state at the return point, not just on
the externally visible state. However, return point oracles may also be
subject to FEP – in this case, called internal FEP (intFEP). In fact, in a
specific program execution, the error, which we assume as detectable
externally in other executions, might generate an internal state which differs
from the expected one, but such a difference might disappear when the
execution proceeds from the faulty statement to the return statement, where no
state difference with respect to the expected state is observed.

⬇

int f(int x) {

// pp0: assert(\old(x) == x))

x = 3 * x; // fix: x = 2 + x;

// pp1: assert(\old(x) + 2 == x))

if (x > 0) {

// pp2: assert(2+\old(x) > 0 && \old(x)+2 == x))

x = x % 4;

// pp3: assert(2+\old(x) > 0 && (\old(x)+2) % 4 == x))

} else {

// pp4: assert(2+\old(x) <= 0 && \old(x)+2 == x))

x = x + 1;

// pp5: assert(2+\old(x) <= 0 && \old(x)+3 == x))

}

// pp6: assert(2+\old(x) > 0 ? \result == (2+\old(x)) % 4 : \result ==
3+\old(x));

return x;

}

void test0() { assert(f(4) == 2); } // FAIL

void test1() { assert(f(5) == 3); } // PASS

Figure 1: Code example including 7 possible internal oracle placement points,
pp0 to pp6, as well as a test case (test0) exhibiting no FEP and one with
external FEP (test1)

In the running example shown in Figure 1, consider the faulty statement `x = 3
* x`, whose corresponding fixed version is `x = 2 + x`, and the return point
assertion at pp6. If the faulty program is executed with input x==4 (see
`test0` in Figure 1), it returns 0, while the expected value is 2, which
indicates the fault can indeed affect an externally visible result, in some
execution. If the program is executed with input x==5, we can observe a
different execution state at program points pp1 and pp2, where we have x==15
in the faulty program, while we expect x==7. However, at program point pp3 the
same value of x is produced by both the faulty and the fixed program: x==3.
When the assertion at pp6 is executed, no difference is observed between
faulty and fixed program. The external assertion inside `test1` also does not
fail.

In the second program execution (with input x==5), the error fails to
propagate to the assertion at pp6 because the information about the different
execution states in the faulty and fixed programs is destroyed by the
execution of statement x = x % 4, which collapses the two different program
states into the same one, x==3. This is a case of both internal and external
FEP, which could be solved by introducing the internal assertion at pp1 or
pp2.

Consider a case where external/output FEP occurs, while internal FEP does not.
Suppose we change the return type of f in the example shown in Figure 1 to
`boolean` and change the return expression to `(x >= 0)`. With such a change,
`test0` would pass, expecting and observing `true` as return value. However,
the return point assertion at pp6 would fail, since the observed value x=0
differs from the expected value x=2.

######  Definition 1 (Internal/External/System FEP)

Given a fault $f$ at program point $pp_{f}$, a specific method execution $e$
containing $pp_{f}$, represented as the sequence of program points $e=\langle
pp_{0},\ldots,pp_{n}\rangle$, is said to be subject to
internal/external/system failed error propagation (intFEP, extFEP, sysFEP) if
execution of the faulty statement $pp_{f}$ causes a state divergence between
actual and expected execution states, $s[pp_{f}]$ and
$s^{\prime}[pp^{\prime}_{f}]$, which is not observable respectively at the
return statement $pp_{n}$ (intFEP), outside the faulty method (extFEP) or in
the output produced by the system (sysFEP):

$\displaystyle\textstyle{intFEP}:$ $\displaystyle s[pp_{f}]\neq
s^{\prime}[pp^{\prime}_{f}]\wedge s[pp_{n}]=s^{\prime}[pp^{\prime}_{n}]$
$\displaystyle\textstyle{extFEP}:$ $\displaystyle s[pp_{f}]\neq
s^{\prime}[pp^{\prime}_{f}]\wedge ext=ext^{\prime}$
$\displaystyle\textstyle{sysFEP}:$ $\displaystyle s[pp_{f}]\neq
s^{\prime}[pp^{\prime}_{f}]\wedge out=out^{\prime}$

where program points $pp^{\prime}_{f},pp^{\prime}_{n}$ correspond to
$pp_{f},pp_{n}$ in the fixed program; $s$ and $s^{\prime}$ indicate the
execution state of faulty and fixed program respectively; $ext$ and $out$ are
the values output by the unit and the system respectively.

Figure 2: Execution points where state corruption disappears in case of internal, external or system FEP Table 1: Studies on Failed Error Propagation Study | Language | Fault Type | Number of Faults | FEP Type | FEP Ratio
---|---|---|---|---|---
Daran et al. [11] | C | Real | 12 | FEP | 78%
Masri et al. [28], Masri & Assi [29, 30] | Java, C | Seeded | 148 | CC, FEP | 56.4%, 15.7%
Wang et al. [44] | C | Mutants | 3000 | CC | 36%
|  | Real | 38 | CC | 53.75%
Miao et al. [32] | C | Seeded | 115 | CC | 56.26%
Li & Liu [24] | C | Seeded | 18 | CC | 20.4%
Xue et al. [50] | Java | Seeded | 19 | CC | 7.4%
Androutsopoulos et al. [3] | C | Mutants | 1408 | CC, FEP | 4.89%, 9.85%
Xiong et al. [48] | Java | Mutants | 137 | FEP | 43.4%
This paper | Java | Real Faults | 386 | FEP (Unit-level) | 0%
|  | Mutants | 1125 | FEP (Unit-level) | 3.7%
|  | Real Faults | 132 | FEP (System-level) | 11.4%

It can be easily shown that internal FEP subsumes external FEP, which in turn
subsumes system FEP (intFEP $\Rightarrow$ extFEP $\Rightarrow$ sysFEP). Figure
2 shows the three cases of FEP in graphical form. When a state corruption
occurs in the execution (red leftmost dot), it might no longer be observable
in the execution right before the return point (green dot labeled intFEP),
right after the return point (extFEP dot) or when the entire system execution
is over (sysFEP dot). Visually, the subsumption relation corresponds to the
green dot (second from left) in the figure, which propagates from left to
right (i.e., if a state corruption disappears, it remains unobservable until
the end of the execution).

##  3 Background and Related Work

###  3.1 Sensitivity Analysis

Voas and Jeffrey [41] introduced the Propagation, Infection, Execution (PIE)
framework to estimate three probabilities: 1) the probability that a
particular section of a program is executed, 2) the probability that the
executed section affects the data state, and 3) the probability that the
affected data state has an effect on the program output. This approach was
also reiterated in the Reachability-Infection-Propagation (RIP) model
described in Amman and Offutt [1].

Based on the PIE framework, Voas et al. [40] proposed a testability technique
called ”sensitivity analysis”, which is the process of determining the
sensitivity of a location in a program. Here the word ”sensitivity” means a
prediction of the probability that a fault will cause a failure in the
software at a particular location under a specified input distribution.
Sensitivity analysis estimates the probability that a code location will be
executed, the probability that faults will cause data-state errors, and the
probability that data-state errors will change the program’s behaviour.
Execution probability can be estimated by simply running the program, and
seeing how often each location is executed. To estimate the probability that
faults will cause data state errors, sensitivity analysis must simulate
various faults, and in order to estimate the probability that data-state
errors will affect the program’s output, sensitivity analysis must simulate
different data-state errors. An empirical evaluation of this idea is lacking
in the paper. However, the described sequence of actions has become the
standard experimental procedure adopted by existing works dealing with FEP.

The later work by Voas and Miller [42] views each location in the program as a
point where an assertion checking the internal state can be placed. The
authors advocate a middle ground between no assertions at all (the most common
practice) and the theoretical ideal of assertions at every location,
introducing the problem of optimal oracle placement. The authors propose
locations determined by sensitivity analysis for the assertion placement. This
idea was used in later works for determining the optimal data set for output-
based oracles [39] and for determining locations to place input-specific
internal oracles [48].

###  3.2 FEP in Different Studies

A number of studies provide evidence of the occurrence of FEP. The motivations
for these studies vary. Some of them analyse specific cases such as
propagation of error codes in file systems [14, 35, 36]. However, the majority
are motivated by FEP being undesirable for Coverage-Based Fault Localization
(CBFL) techniques [46, 5, 18]. Therefore, there is a large body of work aiming
to reduce the vulnerability of CBFL to FEP and this usually includes measuring
the prevalence of FEP in the subjects of the experiments [28, 29, 30, 32, 24,
50, 51]. The work by Xiong et al. [48] analyses FEP to demonstrate that faults
cannot always be captured by traditional output-based oracles and oracles
defined on internal states of the software can further improve the power of
testing systems. Androutsopoulos et al. [3] introduce an information theoretic
formulation of FEP based on measures of conditional entropy, as well as 5
metrics that are well-correlated with FEP.

However, all of these studies use different terms (error masking, fault
masking, strong/weak coincidental correctness) and definitions to express
closely related notions, or use the same term with different meanings. To make
existing studies comparable, we unify existing terms and definitions as
follows, using the PIE framework as a well understood basis for unification:

  * •

Coincidental Correctness (CC) occurs when a fault is executed, but is not
propagated to the output.

  * •

Failed Error Propagation (FEP) occurs when a fault is executed, it infects the
data state, but it does not propagate to the output.

Table 1 provides an overall summary of the studies on FEP. As we can see from
the table, previous work tends to suggest that there is a nontrivial
proportion of faults that are subject to FEP. However, the ratio of FEP varies
across different studies substantially: from 7.4% to 78%. The majority of
these studies come from fault localisation and 4 out of 8 studies in the table
use subjects from the same Siemens Suite. The majority of the studies use
mutants or seeded faults, which are used to simulate real faults. Two studies
[11, 44] analysing real faults use a single C subject and considering
respectively 12 and 38 real faults for it. Only two previous papers considered
FEP for Java programs. However, neither of them attempted to measure FEP on
real faults.

##  4 Experimental Procedure

In this section, we provide the details of the procedure followed in this
paper to measure FEP on real faults. We first present the benchmark used in
the empirical study. To obtain statistically significant measurements we
needed large pools of inputs exercising the faulty statements. We describe the
automated test case generation approach adopted this purpose. Then, we
describe how execution traces of faulty and fixed programs have been aligned
so as to compute state differences at corresponding program points. Finally,
we give detailed information on how the FEP measures were obtained from the
aligned traces.

###  4.1 Benchmark

To analyse FEP in programs with real faults we used Defects4J [22][20], a
large scale database of existing faults, which contains 395 real bugs from 6
real-world Java open source projects (442 classes and 71455 SLOC per project
on average).

For each bug we identify whether it is suitable for our study by checking if
its fix is a change in a method/constructor. The results show that for 9 out
of 395 bugs, the fix is a change in other class members as instance/static
variables, static initialisation blocks or in the class declaration itself (as
the interfaces it implements). We exclude these bugs from our study. For
system-level FEP analysis we can use only bugs from projects with system-level
functionality. This condition is satisfied for 132 bugs from the Closure
Compiler project, as the remaining 5 projects in Defects4J are libraries. For
unit-level FEP analysis we exclude methods/constructors with only one
statement, as there is no possibility for internal or external FEP in them.

Table 2 shows the projects contained in Defects4J, the number of bugs and
changed methods/constructors for each of them. In total, we have 386 bugs and
459 methods/constructors available for unit-level FEP analysis and 132 bugs
available for system-level FEP analysis.

Table 2: Defects4J Projects (M/C means Methods/Constructors) Project Name | Bugs | Number of M/C
---|---|---
| Fix in M/C | All | ¿ 1 LOC | All
JFreeChart | 25 | 26 | 36 | 39
Closure Compiler | 132 | 133 | 153 | 172
Commons Lang | 62 | 65 | 73 | 84
Commons Math | 104 | 106 | 126 | 146
Mockito | 37 | 38 | 31 | 68
Joda Time | 26 | 27 | 40 | 51
Total | 386 | 395 | 459 | 560

###  4.2 Input Generation

As FEP might occur only for specific inputs, to measure its probability we
need a large number of executions that cover the faulty statements.

To obtain these executions for unit-level FEP analysis, we extended the
EvoSuite [12] test case generator. We identify the difference between the
buggy and fixed versions of the method in terms of lines of code. The standard
line coverage criteria of EvoSuite aims at generating a test suite that covers
all lines of code. However, we need to cover only lines of code that contain
faulty statements. Moreover, we need these lines of code to be covered
multiple times, by different test cases. For this purpose, we made changes to
EvoSuite’s implementation, so as to handle the following new parameters:

  1. 1.

line_list: list of lines of code to be covered by the generated test cases;

  2. 2.

goals_multiply: number of times each line should be covered.

In our experiments we aimed to have 1,000 different executions covering each
fault. This number of executions was judged a good balance between the total
time spent on each experiment and the resulting size of the test pool per bug.
Achieving a coverage goal results in a single execution that covers a single
line. Each bug consists of a number of lines, the lines in line_list.
Therefore, we calculate the value for the parameter goals_multiply by dividing
1,000 by the size of the list provided as the line_list parameter and round
this number. We run our extension of EvoSuite giving it a cumulative, maximum
search budget of 10,000 seconds (i.e., a maximum of 10 seconds per coverage
goal).

For system-level FEP analysis, we needed inputs for Closure Compiler, which is
a tool that accepts a JavaScript file as an input, analyzes it, removes dead
code and rewrites and minimizes what’s left. We downloaded the 15 most highly
trending JavaScript projects from
GitHub111https://github.com/trending/javascript, downloaded on 18.09.2017,
containing 3779 JavaScript files in total, and used these files as inputs to
our system.

###  4.3 Trace Alignment

To identify the cases of internal and external FEP, we trace both faulty and
fixed methods, and we compare the values of variables at corresponding program
points in the faulty and fixed versions of the method. In simple scenarios,
where the fault fix requires only a change in an existing statement, the
correspondence between program points is trivially by position in the linearly
ordered sequence of statements, i.e., corresponding program points are program
points with the same line number. However, in more complex cases, in which the
fix requires the addition of new statements and/or the deletion of existing
statements, the statement sequences aligned by order must exclude program
points that refer to added/deleted statements. Hence, the identification of
the corresponding statements can be obtained by calculating the tree edit
distance between the Abstract Syntax Trees (AST) of faulty and fixed methods.
The tree edit distance [38] is the minimal-cost sequence of node edit
operations that transform one tree into another, where the allowed edit
operations are: CHANGE, INSERT, DELETE.

We represent the source code of faulty and fixed versions of a method as an
AST using JavaParser222http://www.javaparser.org. We adapted the tree edit
distance computation algorithm described in [38] so that it works with nodes
which are objects of JavaParser’s `Node` type. We assign the cost of 1 to the
three edit operations (CHANGE, INSERT and DELETE) supported by the algorithm.
As a result, we get an edit sequence which converts one tree into another and
therefore a faulty method into the fixed one.

⬇ 1 public int test(int x) { 2 //pp0 (b, c, d) 3 int y = x + 1; 4 //pp1 (b, c) 5 y = y % 4; 6 //pp2 (b, c) //pp1 (d) 7 return y; 8 } |
---|---
(a)
⬇ 1 public int test(int x) { 2 //pp0 3 int y = x + 1; 4 //pp1 5 y = y % 3; 6 //pp2 7 return y; 8 } |

    KEEP int y = x + 1;
    CHANGE y = y % 4; to
           y = y % 3;
    KEEP return y;

(b)
⬇ 1 public int test(int x) { 2 //pp0 3 int y = x + 1; 4 y = y * 3; 5 //pp1 6 y = y % 4; 7 //pp2 8 return y; 9 } |

    KEEP int y = x + 1;
    INSERT y = y * 3;
    KEEP y = y % 4;
    KEEP return y;

(c)
⬇ 1 public int test(int x) { 2 //pp0 3 int y = x + 1; 4 //pp1 5 return y; 6 } |

    KEEP int y = x + 1;
    DELETE y = y % 4;
    KEEP return y;

(d)
Figure 3: Buggy method (a) and hypothetical fixed versions, obtained by
changing an existing statement (b), by adding a new statement (c), or by
removing an existing statement (d)

Figure 3 (a) shows an example of a simple method test(int x), which, for the
purpose of the explanation, we consider as a buggy method. Three hypothetical
fixes are shown in Figure 3 (b), (c), (d), involving respectively the change
of an existing statement, the addition of a new statement and the deletion of
an existing statement. The edit scripts automatically produced by our
implementation of the tree edit distance algorithm are shown in the right
column of the figure.

1 Procedure  _visit(_n, i_)_

Input:

$n$: AST node to be visited

$i$: instrumentation index

2 begin

3 if  _$n$ is labeled as KEEP or CHANGE $\wedge$ type($n$) is not (RETURN or
THROW)_ then

4 while  _next( $n$) is labeled as DELETE or INSERT_ do

5 $n$ := next($n$)

6

7 $i$ := $i$ \+ 1

8 instrumentAfter($n$, $pp_{i}$)

9

10 else

11 visit(next($n$), $i$)

12

13 if  _type( $n$) is not (FOR or WHILE)_ then

14 for  _$m\in$ children($n$)_ do

15 visit($m$, $i$)

16

17

18

19

Algorithm 1 Program point instrumentation

After the edit script is generated, we start the instrumentation process. For
both the buggy and fixed versions of the method we instrument the starting
program point pp0. Then we visit the nodes in the ASTs of the two methods,
according to the pseudocode of Algorithm 1. If a node is associated with the
KEEP or CHANGE operators and if it is not of the RETURN or THROW statement
types, we instrument the program point after this node (line 7), skipping any
sequence of INSERT and DELETE nodes (lines 4-5). Otherwise, if it is
associated with the INSERT or DELETE operators, we skip the program point and
proceed with the next node (line 9). Then, if the node is not a while or for
loop, the visit proceeds recursively on the subtrees (lines 10-12). We exclude
program points within loops because of the practical difficulty of defining
oracles for the program state inside a loop.

By following this procedure, we obtain the program point correspondence
indicated within comments in Figure 3, associating program points in version
(a) with those in (b), (c), (d). The placement of program points in
$\langle$(a), (b)$\rangle$ is straightforward. In case of $\langle$(a),
(c)$\rangle$, the program point before added statement `y = y * 3` is skipped
during the visit of (c) due to the while loop at lines 4-5 in Algorithm 1.
Similarly, the deleted statement `y = y % 4` is jumped over during the visit
of (a). As a consequence, the program point after `y = x + 1` in (a) has no
corresponding program point in (d).

###  4.4 Measuring FEP

Input:

$type$ = $\langle sys$ $\mid$ $unit\rangle$: type of analysis, system-level or
unit-level

$out$, $out^{\prime}$: output of the system, used only for system-level
analysis

$ext$, $ext^{\prime}$: externally observable state after buggy/fixed methods
have been executed

$pp=\langle pp_{0},\dots,pp_{n}\rangle$: program points executed in fixed
method

$pp^{\prime}=\langle pp^{\prime}_{0},\dots,pp^{\prime}_{k}\rangle$: program
points executed in buggy method

$s$, $s^{\prime}$: state by program point in buggy/fixed methods

Result:

fepType: $\langle$ sysFEP $\mid$ intFEP $\mid$ extFEP $\mid$ noFEP $\rangle$

1

2begin

3

4 if  _$type$ = $unit$ $\&\&$ $ext$ $\neq$ $ext^{\prime}$_ then

5 return noFEP

6

7

8 if  _$type$ = $sys$_ then

9 if  _$out$ $\neq$ $out^{\prime}$_ then

10 return noFEP

11

12

13 if  _$ext$ $\neq$ $ext^{\prime}$_ then

14 return closure(sysFEP, $type$)

15

16

17

18 if  _$s[pp_{n}]\neq s^{\prime}[pp^{\prime}_{k}]$_ then

19 return closure(extFEP, $type$)

20

21

22 if  _$pp\neq pp^{\prime}$_ then

23 return closure(intFEP, $type$)

24

25

26 for  _$i\in[1:n-1]$_ do

27 if  _$s[pp_{i}]\neq s^{\prime}[pp^{\prime}_{i}]$_ then

28 return closure(intFEP, $type$)

29

30

31 return noFEP

32

33

where closure(FEP, $type$) applies the implication intFEP $\Rightarrow$ extFEP
$\Rightarrow$ sysFEP when $type$ = $sys$ and intFEP $\Rightarrow$ extFEP when
$type$ = $unit$.

Algorithm 2 Measuring FEP

After running the generated inputs on the instrumented methods, we obtain the
values of variables at each program point, for each execution. Algorithm 2
shows how we identify whether a given execution is subject to FEP.

As shown at lines 2-3, if unit-level FEP analysis is performed and the
externally observable state is affected by the faulty execution as compared to
the fixed execution, we report no FEP. Similarly, if system-level FEP analysis
is performed and the output of the system is affected by the fault, we report
no FEP (lines 5-6). However, if the output of the system remains the same for
the faulty and fixed execution, but the externally visible state is different,
we report system-level FEP (lines 7-8). Otherwise, we check whether the state
at the program point before return is different (lines 9-10) and if it is so,
we report external FEP. If there is no external FEP, and the program points
traversed by the executions in the buggy and fixed methods are different
(lines 11-12), then internal FEP is detected – here, the executions in the
faulty and the fixed methods took different paths, so if we place an internal
oracle in the buggy method checking for the predicates in the path of the
fixed execution, it would detect the fault. In the case that all program
points in the two executions are the same, we iterate through them and report
internal FEP if the state in at least one aligned pair of them is different
(lines 13-15). Finally, it is also possible that for some inputs, the bug in
the method does not lead to any changes at all in the pair of executions being
compared. This is also a case of no FEP (line 16). The FEP value returned by
the algorithm is expanded with the addition of the subsumed values (invocation
of closure in Algorithm 2). This means for instance that if intFEP is reported
for a system level analysis, extFEP and sysFEP are also reported as true.

We run this algorithm for each system or method/constructor execution, as
appropriate, and then we calculate the proportion of either system-level FEP
or unit-level FEP (both internal and external) across all of the executions
that cover the considered fault, to estimate the probability of FEP for such a
fault. In this algorithm, the value of variables at each program point may
represent Java objects that need to be stored and compared with each other.
For this we use the XStream framework333http://x-stream.github.io/, which can
serialize any Java object without requiring their classes to implement the
java.io.Serializable interface (including private and final fields). We
serialize these objects to JSON format and consider two objects equal when
their JSON representations are the same.

##  5 Results

Table 3: Internal and external FEP on real faults (RQ1) Project | Changed | Methods | Number of | Externally | Int | Ext
---|---|---|---|---|---|---
Name | Methods | with TS | Executions | Detectable | FEP | FEP
JFreeChart | 36 | 28 | 18,785 | 10,678 | 0 | 0
Closure Compiler | 153 | 102 | 89,078 | 42,078 | 0 | 0
Commons Lang | 73 | 54 | 35,153 | 24,854 | 0 | 0
Commons Math | 126 | 92 | 78,489 | 45,065 | 0 | 0
Mockito | 31 | 25 | 20,967 | 8,348 | 0 | 0
Joda Time | 40 | 28 | 15,900 | 7,987 | 0 | 0
Total | 459 | 329 | 258,372 | 139,010 | 0 | 0

###  5.1 Research Questions

We have conducted a set of experiments to answer the following research
questions:

  * •

RQ1: What is the prevalence of unit-level failed error propagation with real
faults?

  * •

RQ2: Does the prevalence of unit-level failed error propagation change if real
faults are replaced by mutants?

  * •

RQ3: Does the prevalence of failed error propagation with real faults change
if it is measured at the system level instead of unit level?

RQ1 is the key research question that motivates this study. The answer to this
question has implications for oracle placement. It is potentially relevant for
both practitioners and researchers, since it estimates the probability of
missing / detecting a fault depending on where oracles are placed (i.e.,
internally, at return points, or externally).

While, to the best of our knowledge, no previous study investigated the
occurrence of FEP on real Java faults, there are experimental results [3, 30,
48] on FEP computed when mutations are used as surrogates for real faults in
both Java and C. Such results provide evidence for the occurrence of FEP on
mutants. With RQ2 we want to investigate whether results on mutants correspond
to the results obtained on real faults.

Since a system level execution typically involves a long chain of concatenated
unit level executions, there is potentially more opportunity for a corrupted
state to disappear during such a system-level execution, becoming undetectable
at the output. In RQ3 we want to check whether the prevalence of FEP changes
(and in particular, whether it increases) when we consider test executions at
the system level instead of unit level as expected.

We also report some observations obtained from a qualitative analysis
performed to better understand the patterns of prevalence behind FEP or no
FEP, either with real faults or with mutations, considering the root cause of
each occurrence.

###  5.2 Experimental Data

We have made all experimental data available in a package that can be
downloaded from http://anonymized-for-double-blind-review.

####  5.2.1 RQ1 (FEP in programs with real faults)

Table 3 shows a summary of the results obtained in our experiments. Column
Changed Methods indicates the overall number of methods changed as a result of
a bug fix, while column Methods with TS reports the number of methods for
which our extended version of EvoSuite was able to generate a large test
suite, consisting of test cases that exercise the faulty statements. While the
target size of these test suites was 1,000 test cases, sometimes EvoSuite
generated slightly smaller test suites in the allowed generation time (the
average test suite size is 863).

Column Number of Executions shows the overall number of executions obtained as
a result of running the test cases. Column Externally Detectable shows the
number of executions where the fault resulted in a program state deviation
that is observable outside of the methods. Columns Internal FEP and External
FEP show that, among the 258,372 executions, the fault was externally
observable in 139,010 cases (53.8%). In the remaining cases (119,362 test case
executions), in order for FEP to happen an internal program state deviation,
not propagated to the output, should be observed. However, this was never the
case. There was no single case where an internal state deviation occurred,
i.e. no state infection.

We have tested the statistical significance of our results, which depends on
sample size and observed values. According to the Pearson-Klopper method for
calculating binomial confidence intervals, internal/external FEP is in the
range [0:$1.43^{-5}$] with mean = 0 at confidence level 95%. This means that
even if intFEP and extFEP could occur in other subjects (we might have not
observed it just by chance), their likelihood can be assumed to be very low
with high confidence.

RQ1: Our experiments show that the probability of unit-level FEP in Java
methods with real faults is extremely low.

####  5.2.2 RQ2 (FEP in mutated programs)

Table 4: Methods from benchmark grouped by LOC Project Name | 2-25 | 26-50 | 51- | 101- | ¿200
---|---|---|---|---|---
|  |  | 100 | 200 |
JFreeChart | 22 | 6 | 5 | 3 | 0
Closure Compiler | 60 | 45 | 35 | 8 | 5
Commons Lang | 34 | 16 | 11 | 12 | 0
Commons Math | 59 | 22 | 24 | 16 | 5
Mockito | 25 | 6 | 0 | 0 | 0
Joda Time | 26 | 12 | 2 | 0 | 0

For RQ2, instead of real faults we consider faulty versions of methods
obtained by means of mutation analysis (i.e., we generate mutants of the fixed
Defects4J methods). As we need a large test suite for each mutant and the
number of mutations generated per method can be high, we did not conduct this
analysis on all the methods available in the benchmark. Instead, we sampled
the methods based on their lines of code, we divided methods into 5 groups:
2-25 LOC, 26-50 LOC, 51-100 LOC, 101-200LOC, ¿ 200LOC. Table 4 shows the
number of methods in each group for each project. We randomly selected one
method from each group for each project and we generated mutants for the
selected representative using Major[19] and applying all the mutation
operators available in this tool. Then, among the generated mutations, we
selected only strongly killable mutants, to avoid the inclusion of equivalent
mutants. In fact, an internal state deviation in an equivalent mutant is
always associated with external FEP, but this is by definition a false
positive, because the internally observed difference is not an indicator of a
fault: since the mutant is equivalent to the original program, it does not
introduce any fault into the program, so there is no fault to be detected
internally at all. Hence, we conservatively measure FEP only on mutants proved
to be strongly killable by test generation. In cases when EvoSuite was unable
to generate a large test suite for any of the mutations of a method, or when
none of them is strongly killable, we randomly select another method from the
group.

Table 5: Mutants generated. Project Name | Mutants | Strongly
---|---|---
|  | Killed
JFreeChart | 37 | 25
Closure Compiler | 468 | 350
Commons Lang | 360 | 215
Commons Math | 765 | 502
Mockito | 28 | 15
Joda Time | 212 | 18
Total | 1870 | 1125
Table 6: Internal/external FEP on mutants (RQ2) Project | Num of | Externally | Int | Ext
---|---|---|---|---
Name | Execs | Detectable | FEP | FEP
JFreeChart | 25,842 | 6,217 | 0 | 0
Closure Compiler | 320,678 | 180,562 | 2,587 | 4,783
Commons Lang | 89,043 | 45,800 | 1,567 | 2,623
Commons Math | 422,068 | 200,865 | 10,222 | 25,956
Mockito | 16,284 | 7,321 | 0 | 0
Joda Time | 15,460 | 8,970 | 0 | 0
Total | 889,375 | 449,735 | 14,376 | 33,362

Table 5 shows the overall number of mutants and the number of mutants that are
strongly killable by the generated test suites. We can see from Table 6 that
when we replace real faults with mutations, for 3 subjects there are cases of
both internal and external FEP. Among all 831,789 executions in these 3
subjects, 51% of faults were externally detectable. In 1.6% of executions
there was an occurrence of internal and in 3.7% of external FEP. In the
remaining cases (46.9%) the internal state was always identical to the
expected one, i.e., the fault did not infect the execution.

According to the Pearson-Klopper method, internal FEP is in the range
[0.0159:0.0164], with mean = 0.0161, at confidence level 95%; external FEP is
in the range [0.0210:0.0216], with mean = 0.0213, at confidence level 95%.

RQ2: Mutants behave in a substantially different way than real faults when FEP
is considered for Java methods: there is higher probability of both internal
and external FEP when the fault is introduced by mutation.

####  5.2.3 RQ3 (System-level FEP)

Table 7: System-Level FEP on real faults (RQ3) Closure | Num of | Externally | Sys | Int | Ext
---|---|---|---|---|---
Bug ID | Execs | Detectable | FEP | FEP | FEP
1 | 20 | 12 | 8 | 8 | 8
4 | 15 | 5 | 8 | 0 | 0
8 | 200 | 159 | 41 | 0 | 0
13 | 36 | 24 | 0 | 0 | 0
16 | 15 | 10 | 0 | 0 | 0
20 | 22 | 22 | 0 | 0 | 0
21 | 4 | 4 | 0 | 0 | 0
22 | 4 | 4 | 0 | 0 | 0
29 | 1 | 1 | 0 | 0 | 0
34 | 13 | 10 | 0 | 0 | 0
50 | 1 | 1 | 0 | 0 | 0
52 | 13 | 13 | 0 | 0 | 0
56 | 2 | 2 | 0 | 0 | 0
60 | 5 | 5 | 0 | 0 | 0
62 | 57 | 50 | 0 | 0 | 0
63 | 57 | 50 | 0 | 0 | 0
87 | 23 | 12 | 3 | 0 | 0
115 | 3 | 3 | 0 | 0 | 0
116 | 4 | 4 | 0 | 0 | 0
127 | 14 | 14 | 0 | 0 | 0
131 | 9 | 9 | 0 | 0 | 0
133 | 10 | 10 | 0 | 0 | 0
Total | 528 | 424 | 60 | 8 | 8

For RQ3 we have run Closure Compiler on 5,070 different JavaScript input
files, on 132 bugs of this project. For each bug, we made a run on both faulty
and fixed versions of the system and saved the pairs of outputs and method
executions obtained. The output of Closure Compiler is also a JavaScript file
and if the output files generated are different we consider the execution to
be Externally Detectable. Table 7 lists the ID of the bugs which we were able
to execute with our inputs. 22 bugs out of 132 were executed leading to an
overall number of 528 executions. For each of these 22 bugs there was at least
one execution which was externally detectable, i.e. that caused a change in
the output file generated by Closure Compiler. Overall, 424 out of 528 (80.3%)
executions were externally detectable. 60 executions (11.4%) provide evidence
of FEP in 4 different bugs. For 8 executions (1.5% of all executions) of Bug 1
we observed unit-level internal and external FEP. This bug affects neither the
externally observable state of the class nor the final output of the system.
However, it causes the program states in faulty and fixed versions to differ,
which is evidence of both Internal and External FEP. During the unit-level
analysis our test case generator was not able to generate any test cases for
this bug, therefore no unit-level FEP was reported in RQ1.

According to the Pearson-Klopper method for calculating binomial confidence
intervals, internal FEP is in the range [0.0878:0.1438], with mean = 0.1136,
at confidence level 95%.

RQ3: The prevalence of FEP changes when we test programs at the system level
instead of unit level: 11.4% of the overall executions provide evidence of
system-level FEP, which is substantially higher than the probability of unit-
level FEP, both with real faults and with mutants.

####  5.2.4 Qualitative analysis of factors affecting FEP

To understand the reasons behind the absence of FEP in unit level programs
with real faults and their existence in the mutations of these, we performed a
qualitative analysis on all of the 386 bugs from the Defects4J benchmark and
all of the mutations generated by Major. For methods from Defects4J, we
manually compared the buggy version of the methods with the fixed version and
analysed the bug fixes. As a result of this analysis we identified two major
classes of explanations for the absence of FEP: (1) the fix of the bug affects
the output directly; (2) the state change resulting from the fix is such that
it must necessarily propagate to the output. In case (1), clearly both
internal and external FEP are impossible, since all state deviations are
immediately returned to the external oracle. In case (2), the state change
propagates to the output because the computation performed between the fault
and the return statement does not “squeeze” the state [3].

##### Bug fix affects the output directly

⬇

1 public static LocalDate fromDateFields(Date date) {

2 if (date == null)

3 throw new IllegalArgumentException

4 ("The date must not be null");

5 // if (date.getTime() < 0) {

6 // GregorianCal cal = new GregorianCal();

7 // cal.setTime(date);

8 // return fromCalendarFields(cal);

9 // }

10 return new LocalDate(

11 date.getYear() + 1900,

12 date.getMonth() + 1,

13 date.getDate());

14 }

Figure 4: Joda Time Bug 12

During manual analysis, one commonly occurring fix pattern was a change in the
return statement of a method. As fix changes the return statement directly, it
is not possible to observe any difference between the fixed and buggy versions
at some internal point in the method, so no FEP can be observed in such cases.
A variant of this pattern is the addition of an if statement containing return
or throw statements inside. In Figure 4 the bug is fixed by adding the if
statement at lines 5-9. So whenever this if statement is executed, the method
will return the object produced by the invocation at line 8. If this differs
from the object generated by the faulty version at line 10, the difference
will be definitely observable by an external oracle. If it does not differ, we
have coincidental correctness, but no FEP.

Table 8: Fix propagation patterns Project | Fixed | Change | Add | Bugs | Prop
---|---|---|---|---|---
| meth- | return | if |  | to
| ods |  |  |  | out
JFreeChart | 36 | 11 | 3 | 25 | 8
Closure Compiler | 153 | 21 | 13 | 131 | 14
Commons Lang | 73 | 17 | 10 | 61 | 4
Commons Math | 126 | 28 | 28 | 104 | 17
Mockito | 31 | 9 | 6 | 37 | 1
Joda Time | 40 | 9 | 6 | 26 | 4
Total | 459 | 95 | 66 | 384 | 48

To quantify this class of FEP, we considered the edit scripts generated for
trace alignment: (1) when the edit script contains a CHANGE operator which
changes one return statement into another; or, (2) when the edit script
contains an INSERT operator which adds an if statement containing a return or
throw statement inside. Table 8 (col. 3-4) reports the number of occurrences
of both cases. As we can see, in 35% of the methods the bug fix includes these
type of changes.

##### Change always propagates to output

⬇

1 public double getChiSquare() {

2 double chiSquare = 0;

3 for (int i = 0; i < rows; ++i) {

4 final double residual = residuals[i];

5 chiSquare += residual * residual *

6 residualsWeights[i];

7 //chiSquare += residual * residual /

8 // residualsWeights[i];

9 }

10 return chiSquare;

11 }

Figure 5: Commons Math Bug 65

Another typical pattern preventing the occurrence of FEP is when a state
change resulting from a bug fix always propagates to output. In Figure 5 the
bug is at lines 5-6 and the fix is as indicated at lines 7-8. If the buggy
statement is executed, it might cause a difference in the value of the
chiSquare variable. However, whenever this happens, this different value is
ensured to always propagate to the return statement, hence being externally
observable. When there is no difference, we have coincidental correctness, but
no FEP.

Table 8 (col. 5-6) shows the number of bugs for each project where this
scenario holds. These cases were identified by performing a manual analysis of
the fixed bug. Overall, it happens in 13% of the bugs.

##  6 Implications

The empirical results presented in this paper have relevant implications for
practitioners and researchers:

##### Internal oracles

The absence of internal FEP when real faults are considered for Java units
(classes) indicates that internal oracles do not have higher fault detection
capabilities than return point or external oracles when performing unit
testing of classes. Rather than attempting to include assertions about the
internal execution state, Java developers might better invest their time to
strengthen the assertions that check the program state at return points or
within test cases. In fact, if such assertions are sufficiently strong to
capture any deviation from the expected execution state, they should miss no
fault that manifests itself internally, because the internal state deviation
tends to reach them. Researchers interested in Java faults should focus on
techniques to improve the oracles that can be defined at return points or
within test cases, because these can be made equally effective as internal
oracles.

The non-negligible occurrence of FEP at the system level indicates that
checking the overall output of a system might be not enough and that probes
for the intermediate computations should be inserted into the test case
execution to avoid that the effects of faults disappear when proceeding to the
computation of the overall system output. While such intermediate oracles can
still be based on post conditions or test case assertions, and do not require
the observation of internal execution states, they might represent a challenge
for system level testing. In fact, at this testing level the system is usually
considered as a black box, whose intermediate steps are not visible. According
to our results, monitoring and checking such intermediate steps is quite
important for avoiding system FEP.

##### Post-conditions

The programming by contract method prescribes that every method be equipped
with pre-conditions, post-conditions and invariants. This approach to
programming offers several benefits, among which are the following
possibilities: to formally express the specifications that each method must
satisfy, in a way that is machine interpretable; to reuse the oracle across
test cases; to document a method in an unambiguous way. One may question what
part of the execution state should be checked in a post-condition. In fact, at
return points the whole internal state of the method under test is accessible.
According to our results, the absence of internal FEP indicates that checking
the externally visible effects of a method execution is enough to expose
faults as soon as they corrupt the execution state. It is unlikely that the
effort of creating internal oracles be beneficial to early fault exposure.
Rather, postconditions at return points can be focused on the externally
visible effects of the execution, disregarding the inner details. This is
consistent with the programming by contract paradigm, where only the
externally visible contract is typically specified.

##### Subsystem testing

The higher prevalence of failed error propagation at system level over unit
level might indicate that testing subsystems of the software in isolation
could make it easier to expose bugs. While the effect of a bug is externally
visible in the class to which it belongs, it is not always visible at the
level of the whole system. This might support the idea of bottom-up
integration testing, in which we build on unit-level results by testing
higher-level combination of units in successively more complex scenarios.

##### Mutants vs. real faults

The software engineering community has witnessed a long debate on the use of
mutants as surrogate for real faults [2, 23]. Such a replacement may be valid
for the purpose of evaluating the adequacy of a test suite, owing to the high
correlation between mutation score and fault detection rate. We are interested
in investigating the propagation of an error to the oracle that can detect it.
Our results show that such propagation is prevalent with mutants, while it is
absent with real faults. Our qualitative analysis indicates that mutants
corrupt the internal state differently from real faults. In fact, the latter
state corruption tends to always generate an externally visible misbehaviour,
while the former might remain invisible if only the external state is
inspected. Hence, practitioners should not decide where to place their oracles
based on the propagation of errors as simulated with mutants. Researchers
could investigate mutation operators that behave similarly to real faults with
respect to the propagation of the corrupted internal state to the externally
visible state.

##### Previous work

As discussed in Section 6, previous work on failed error propagation tended to
suggest that there is a nontrivial proportion of faults that manifest this FEP
property. Our results differ markedly from these previous findings. One
possible explanation could be differences in the subjects and the types of
faults. Daran et al. [11] analysed 12 real faults in a C program with 1000
lines of code. Wang et al. [44] analysed 38 real faults in a C program with
6000 lines of code. By comparison the Defects4J contains 395 real faults which
come from six large Java projects. An intriguing possibility lies in the
potential differences between the two language (C vs. Java) styles; perhaps
some programming languages have inherently higher or lower failed error
propagation propensity than others. Hence, one of the implications of our
findings is the pressing need for further work on FEP in different programming
languages and corpuses. Taken together, our findings and those in the previous
literature do tend to suggest that there may be differences between different
programming paradigms with respect to error propagation behaviour, and that
there are certainly differences between unit and system level FEP. These
differences clearly have implications for software testability [9, 43],
because FEP tends to inhibit testability. Such findings may also suggest
testability transformations [16, 31] that could reduce the likelihood of
failed error propagation, leading to reformulations of software systems (e.g.,
by inserting probes for intermediate steps) that are inherently more testable.

###  6.1 Threats to Validity

Threats to external validity affect the generalisation of our results. We
carried out our experiments on a well established benchmark for Java,
Defects4J, which includes 395 real bugs from 6 different projects. While
Defects4J is becoming de-facto a standard benchmark for Java testing,
replication of our study on further subjects beyond Defects4J would be quite
important. We do not claim generalisability to programming languages other
than Java. On the contrary, we suspect that the programming style of Java,
which encourages the decomposition of the software into small computations
assigned to methods, favours the creation of code units where information is
not squeezed when propagating from inner states to the output. Other
programming styles might favour the creation of longer and more complex
computational units, where information squeezing might be more likely to
occur.

Threats to internal validity come from factors that could influence our
results. Among them, the most important factor that influences our conclusions
on the differences between real faults and mutants on FEP, is the set of
mutations that have been considered. To limit such a threat, we used a well-
established mutation analysis tool, Major. However, different tools and
different mutation operators might lead to different sets of synthetic faults.
Moreover, we have not been able to perform mutation analysis of all the buggy
methods available in Defects4J, because of the enormous computation time
involved, since we generate test cases for all mutants that Major produces for
each method. We have defined a sampling strategy that takes method size into
account, in order to consider representatives of the various possible method
size categories. However, this does not ensure that the results obtained on
the selected sample would remain exactly the same if extended to the entire
dataset of the buggy methods.

##  7 Conclusion

In this paper we have presented empirical evidence from a large corpus of
real-world faults in Java systems that reveals a surprisingly low unit-level
FEP amongst the 386 faults studied. On the other hand, with system-level
inputs we get a substantially higher rate of FEP. This shows that when oracles
are defined for an individual Java class, postconditions that predicate on the
externally observable state or test case oracles are sufficient to detect
faults as soon as they corrupt the internal state. On the contrary, when we
analyse a complete software system, the output alone does not provide enough
information to expose faults as soon as they manifest themselves,
necessitating the observation of intermediate computation steps.

When we turn our attention to studying the synthetic faults introduced by
program mutants (a widespread practice believed to be good at simulating real
faults), we find noticeably different behaviour at the unit level: the
artificial faults denoted by mutants do exhibit substantial FEP, unlike the
real faults we studied. While such synthetic faults may be good proxies for
estimating whether test cases that reveal them will also reveal real faults,
there do appear to be non-trivial differences in the behaviour of synthetic
faults and real faults, with respect to their error propagation in Java
classes.

These findings suggest further work to investigate the prevalence of FEP in
other programming languages and bug data sets, and the need to further
investigate the relationship between mutation testing and real faults. We
studied only single faults, but future work could also extend our findings to
multiple faults, which may have additional implications for higher order
mutation testing, one of the main motivations of which is the ability to model
fault masking.

## References

  * [1] P. Ammann and J. Offutt.  Introduction to Software Testing.  Cambridge University Press, New York, NY, USA, 1 edition, 2008.
  * [2] J. H. Andrews, L. C. Briand, and Y. Labiche.  Is mutation an appropriate tool for testing experiments?  In 27th International Conference on Software Engineering (ICSE), pages 402–411, 2005.
  * [3] K. Androutsopoulos, D. Clark, H. Dan, R. M. Hierons, and M. Harman.  An analysis of the relationship between conditional entropy and failed error propagation in software testing.  In 36th International Conference on Software Engineering, ICSE, pages 573–583, 2014.
  * [4] T.-D. B. Le, D. Lo, C. Le Goues, and L. Grunske.  A learning-to-rank based fault localization approach using likely invariants.  In Proceedings of the 25th International Symposium on Software Testing and Analysis, ISSTA 2016, 2016.
  * [5] B. Baudry, F. Fleurey, and Y. Le Traon.  Improving Test Suites for Efficient Fault Localization.  In 28th International Conference on Software Engineering (ICSE 06), Shanghai, China, 2006. ACM.  selection : 9%.
  * [6] B. Beizer.  Software Testing Techniques.  Van Nostrand Reinhold, 1990.
  * [7] H. Bengtsson.  Linux settimelimit bug description.
  * [8] A. Bertolino.  Software testing research: Achievements, challenges, dreams.  In L. Briand and A. Wolf, editors, Future of Software Engineering 2007, Los Alamitos, California, USA, 2007. IEEE Computer Society Press.
  * [9] R. V. Binder.  Design for testability in object–oriented systems.  Communications of the ACM, 37(9):87–101, 1994.
  * [10] S. Chandra and P. M. Chen.  How fail-stop are faulty programs?  In 28th IEEE Symposium on Fault Tolerant Computing Systems (FTCS-28), pages 240–249, June 1998.
  * [11] M. Daran and P. Thévenod-Fosse.  Software error analysis: A real case study involving real faults and mutations.  In Proceedings of the 1996 ACM SIGSOFT International Symposium on Software Testing and Analysis, ISSTA ’96, pages 158–171, New York, NY, USA, 1996. ACM.
  * [12] G. Fraser and A. Arcuri.  EvoSuite: automatic test suite generation for object-oriented software.  In $8^{th}$ European Software Engineering Conference and the ACM SIGSOFT Symposium on the Foundations of Software Engineering (ESEC/FSE ’11), pages 416–419. ACM, September 5th - 9th 2011.
  * [13] M. Grottke and K. Trivedi.  A classification of software faults.  In Supplemental Proc. Sixteenth International IEEE Symposium on Software Reliability Engineering, pages 4.19 – 4.20, 2005.
  * [14] H. S. Gunawi, C. Rubio-González, A. C. Arpaci-Dusseau, R. H. Arpaci-Dussea, and B. Liblit.  Eio: Error handling is occasionally correct.  In Proceedings of the 6th USENIX Conference on File and Storage Technologies, FAST’08, pages 14:1–14:16, Berkeley, CA, USA, 2008. USENIX Association.
  * [15] H. S. Gunawi, C. Rubio-González, A. C. Arpaci-Dusseau, R. H. Arpaci-Dusseau, and B. Liblit.  EIO: Error handling is occasionally correct.  In M. Baker and E. Riedel, editors, 6th USENIX Conference on File and Storage Technologies (FAST 2008), pages 207–222, 2008.
  * [16] M. Harman, L. Hu, R. M. Hierons, J. Wegener, H. Sthamer, A. Baresel, and M. Roper.  Testability transformation.  IEEE Transactions on Software Engineering, 30(1):3–16, Jan. 2004\.
  * [17] Y. Jia and M. Harman.  An analysis and survey of the development of mutation testing.  IEEE Transactions on Software Engineering, 37(5):649 – 678, September–October 2011.
  * [18] J. A. Jones.  Fault localization using visualization of test information.  In Proceedings. 26th International Conference on Software Engineering, pages 54–56, May 2004.
  * [19] R. Just.  The Major mutation framework: Efficient and scalable mutation analysis for Java.  In Proceedings of the International Symposium on Software Testing and Analysis (ISSTA), pages 433–436, San Jose, CA, USA, July 23–25 2014\.
  * [20] R. Just, D. Jalali, and M. D. Ernst.  Defects4j: A database of existing faults to enable controlled testing studies for java programs.  In Proceedings of the 2014 International Symposium on Software Testing and Analysis, ISSTA 2014, pages 437–440, New York, NY, USA, 2014. ACM.
  * [21] R. Just, D. Jalali, L. Inozemtseva, M. D. Ernst, R. Holmes, and G. Fraser.  Are mutants a valid substitute for real faults in software testing?  In Proceedings of the 22Nd ACM SIGSOFT International Symposium on Foundations of Software Engineering, FSE 2014, 2014.
  * [22] R. Just, D. Jalali, L. Inozemtseva, M. D. Ernst, R. Holmes, and G. Fraser.  Are mutants a valid substitute for real faults in software testing?  In International Symposium on Foundations of Software Engineering (FSE), pages 654–665, 2014.
  * [23] R. Just, D. Jalali, L. Inozemtseva, M. D. Ernst, R. Holmes, and G. Fraser.  Are mutants a valid substitute for real faults in software testing?  In Proceedings of the 22nd ACM SIGSOFT International Symposium on Foundations of Software Engineering (FSE), pages 654–665, 2014\.
  * [24] Y. Li and C. Liu.  Using cluster analysis to identify coincidental correctness in fault localization.  In Computational and Information Sciences (ICCIS), 2012 Fourth International Conference on, pages 357–360. IEEE, 2012.
  * [25] Y. Lu, Y. Lou, S. Cheng, L. Zhang, D. Hao, Y. Zhou, and L. Zhang.  How does regression test prioritization perform in real-world software evolution?  In Proceedings of the 38th International Conference on Software Engineering, ICSE ’16, 2016.
  * [26] L. Ma, C. Artho, C. Zhang, H. Sato, J. Gmeiner, and R. Ramler.  Grt: Program-analysis-guided random testing (t).  In 2015 30th IEEE/ACM International Conference on Automated Software Engineering (ASE), 2015.
  * [27] M. Martinez and M. Monperrus.  Astor: A program repair library for java (demo).  In Proceedings of the 25th International Symposium on Software Testing and Analysis, ISSTA 2016, 2016.
  * [28] W. Masri, R. Abou-Assi, M. El-Ghali, and N. Al-Fatairi.  An empirical study of the factors that reduce the effectiveness of coverage-based fault localization.  In Proceedings of the 2nd International Workshop on Defects in Large Software Systems: Held in conjunction with the ACM SIGSOFT International Symposium on Software Testing and Analysis (ISSTA 2009), pages 1–5. ACM, 2009.
  * [29] W. Masri and R. A. Assi.  Cleansing test suites from coincidental correctness to enhance fault-localization.  In Software Testing, Verification and Validation (ICST), 2010 Third International Conference on, pages 165–174. IEEE, 2010.
  * [30] W. Masri and R. A. Assi.  Prevalence of coincidental correctness and mitigation of its impact on fault localization.  ACM Trans. Softw. Eng. Methodol., 23(1):8:1–8:28, 2014.
  * [31] P. McMinn.  Search-based failure discovery using testability transformations to generate pseudo-oracles.  In F. Rothlauf, editor, Genetic and Evolutionary Computation Conference (GECCO 2009), pages 1689–1696, Montreal, Québec, Canada, 2009\. ACM.
  * [32] Y. Miao, Z. Chen, S. Li, Z. Zhao, and Y. Zhou.  Identifying coincidental correctness for fault localization by clustering test cases.  In SEKE, pages 267–272, 2012.
  * [33] S. Pearson, J. Campos, R. Just, G. Fraser, R. Abreu, M. D. Ernst, D. Pang, and B. Keller.  Evaluating and improving fault localization.  In Proceedings of the 39th International Conference on Software Engineering, ICSE ’17, 2017.
  * [34] B. Randell.  On failures and faults.  In K. Araki, S. Gnesi, and D. Mandrioli, editors, International Symposium of Formal Methods Europe (FME), volume 2805 of Lecture Notes in Computer Science, pages 18–39. Springer, 2003.
  * [35] C. Rubio-González, H. S. Gunawi, B. Liblit, R. H. Arpaci-Dusseau, and A. C. Arpaci-Dusseau.  Error propagation analysis for file systems.  In Proceedings of the 30th ACM SIGPLAN Conference on Programming Language Design and Implementation, PLDI ’09, pages 270–280, New York, NY, USA, 2009. ACM.
  * [36] C. Rubio-González, H. S. Gunawi, B. Liblit, R. H. Arpaci-Dusseau, and A. C. Arpaci-Dusseau.  Error propagation analysis for file systems.  SIGPLAN Not., 44(6):270–280, June 2009.
  * [37] S. Shamshiri.  Automated unit test generation for evolving software.  In Proceedings of the 2015 10th Joint Meeting on Foundations of Software Engineering, ESEC/FSE 2015, 2015.
  * [38] D. Shasha and K. Zhang.  Approximate tree pattern matching, pages 341–371.  Oxford University Press, 1997.
  * [39] M. Staats, G. Gay, and M. P. E. Heimdahl.  Automated oracle creation support, or: How I learned to stop worrying about fault propagation and love mutation testing.  In 34th International Conference on Software Engineering, ICSE 2012, June 2-9, 2012, Zurich, Switzerland, pages 870–880, 2012.
  * [40] J. Voas, L. Morell, and K. Miller.  Predicting where faults can hide from testing.  IEEE Software, 8(2):41–48, March 1991.
  * [41] J. M. Voas.  Pie: A dynamic failure-based technique.  IEEE Trans. Softw. Eng., 18(8):717–727, Aug. 1992.
  * [42] J. M. Voas and K. W. Miller.  Putting assertions in their place.  In Proceedings of 1994 IEEE International Symposium on Software Reliability Engineering, pages 152–157, Nov 1994.
  * [43] J. M. Voas and K. W. Miller.  Software testability: The new verification.  IEEE Software, 12(3):17–28, May 1995.
  * [44] X. Wang, S. Cheung, W. K. Chan, and Z. Zhang.  Taming coincidental correctness: Coverage refinement with context patterns to improve fault localization.  In 31st International Conference on Software Engineering, ICSE 2009, May 16-24, 2009, Vancouver, Canada, Proceedings, pages 45–55, 2009.
  * [45] E. Wong and B. Cukic.  Adaptive Control Approach for Software Quality Improvement.  World scientific Series on Software Engineering and Knowledge Engineering, 2011.  Volume 20.
  * [46] W. E. Wong, Y. Qi, L. Zhao, and K. Y. Cai.  Effective fault localization using code coverage.  In 31st Annual International Computer Software and Applications Conference (COMPSAC 2007), volume 1, pages 449–456, July 2007.
  * [47] Q. Xin and S. P. Reiss.  Identifying test-suite-overfitted patches through test case generation.  In Proceedings of the 26th ACM SIGSOFT International Symposium on Software Testing and Analysis, ISSTA 2017, 2017.
  * [48] Y. Xiong, D. Hao, L. Zhang, T. Zhu, M. Zhu, and T. Lan.  Inner oracles: input-specific assertions on internal states.  In Proceedings of the 2015 10th Joint Meeting on Foundations of Software Engineering, ESEC/FSE, pages 902–905, 2015.
  * [49] Y. Xiong, J. Wang, R. Yan, J. Zhang, S. Han, G. Huang, and L. Zhang.  Precise condition synthesis for program repair.  In Proceedings of the 39th International Conference on Software Engineering, ICSE ’17, 2017.
  * [50] X. Xue, Y. Pang, and A. S. Namin.  Trimming test suites with coincidentally correct test cases for enhancing fault localizations.  In IEEE 38th Annual Computer Software and Applications Conference, COMPSAC 2014, Vasteras, Sweden, July 21-25, 2014, pages 239–244, 2014.
  * [51] Z. Zheng, Y. Gao, P. Hao, and Z. Zhang.  Coincidental correctness: An interference or interface to successful fault localization?  In Software Reliability Engineering Workshops (ISSREW), 2013 IEEE International Symposium on, pages 114–119. IEEE, 2013.