Automated T esting of Refactoring Engines Brett Daniel Danny Dig - - PowerPoint PPT Presentation

automated t esting of refactoring engines
SMART_READER_LITE
LIVE PREVIEW

Automated T esting of Refactoring Engines Brett Daniel Danny Dig - - PowerPoint PPT Presentation

Automated T esting of Refactoring Engines Brett Daniel Danny Dig Kely Garcia Darko Marinov ESEC/FSE 2007 Refactoring engines are tools that automate the application of refactorings 2 Eclipse and NetBeans 3 Why T est Refactoring


slide-1
SLIDE 1

Automated T esting of Refactoring Engines

Brett Daniel Danny Dig Kely Garcia Darko Marinov

ESEC/FSE 2007

slide-2
SLIDE 2

2

Refactoring engines are tools that automate the application of refactorings

slide-3
SLIDE 3

3

Eclipse and NetBeans

slide-4
SLIDE 4

4

Why T est Refactoring Engines?

  • Widely used
  • Complex

– Complex inputs: programs – Require nontrivial program analyses and

transformation

  • Can silently corrupt large bodies of code

Refactoring engines contain bugs

slide-5
SLIDE 5

5

Example: Encapsulate Field

Replaces all field reads and writes with accesses through getter and setter methods

class A { int f; void m(int i) { f = i * f; } } class A { private int f; void m(int i) { setF(i * getF()); } void setF(int f) { this.f = f; } int getF() { return f; } } Encapsulate Field

1 2 4 3 5

slide-6
SLIDE 6

6

Eclipse Bug

Encapsulate Field class A { int f; } class B extends A { void m() { super.f = 0; } } class A { private int f; void setF(int f) { this.f = f; } int getF() { return this.f; } } class B extends A { void m() { super.getF() = 0; } } super.setF(0);

slide-7
SLIDE 7

7

NetBeans Bug

class A { int f; void m() { (new A().f) = 0; } } class A { private int f; void setF(int f) { this.f = f; } int getF() { return this.f; } void m() { (new A().f) = 0; } } Encapsulate Field new A().setF(0);

slide-8
SLIDE 8

8

T esting a Refactoring Engine

Refactoring Engine Program Refactoring Refactored Program Warning Warning Warnings

slide-9
SLIDE 9

9

State of the Practice

  • Manually written tests

– Input: Program files and code to invoke

refactoring

– Output: Hand-refactored program file or

warnings

  • Automatically executed tests

– Eclipse 3.2 has over 2,600 manually-written

JUnit tests

– NetBeans 6.0M3 has 252 XT

est tests

slide-10
SLIDE 10

10

Automated T esting

  • Goal: Automate input generation and
  • utput checking
  • Assumptions

– T

ester has intuition for input programs that might expose bugs

  • e.g. Encapsulating inherited fields

– It is labor-intensive to manually write many

input programs

  • e.g. Thousands of ways to reference an inherited field
slide-11
SLIDE 11

11

Challenges

  • How to “codify” the tester's intuition to

create many interesting programs

  • How to automatically check that

refactoring completes correctly

slide-12
SLIDE 12

12

Solution

  • Developed ASTGen

– Framework for generating abstract syntax

trees

– Provides library of generators that produce

simple AST fragments

– T

ester writes complex generators composed

  • f smaller generators
  • Developed variety of oracles
slide-13
SLIDE 13

13

ASTGen Design Goals

  • Imperative

– T

ester can control how to build complex data

  • Iterative

– Generates inputs lazily, saving memory

  • Bounded-Exhaustive

– Catches “corner cases”

  • Composable

– T

ester can create complex generators by reusing simpler parts

slide-14
SLIDE 14

14

T esting Process

  • T

ester builds a generator using ASTGen

  • T

ester instantiates the generator for the test at hand.

  • T

ester runs generator in a loop. For each generated value:

– Run refactoring – Check oracles

slide-15
SLIDE 15

T esting Encapsulate Field

String fieldName = "f"; IGenerator<Program> testGen = new ...(fieldName); for (Program in : testGen) { Refactoring r = new EncapsulateFieldRefactoring(); r.setTargetField(fieldName); Program out = r.performRefactoring(in); checkOracles(out); }

slide-16
SLIDE 16

16

class A { int f; } class B extends A { void m() { super.f = 0; } }

Example Generator

  • Double-class field reference generator

“Produces pairs of classes related by containment and inheritance. One class declares a field, and the other references the field in some way.”

class A { boolean f; } class B { void m() { new A().f = true; } } class A { int f; class B { void m() { int i = f; } } }

...

slide-17
SLIDE 17

17

class A { int f; } class B extends A { void m() { super.f = 0; } }

Example Generator

“Produces pairs of classes related by containment and inheritance. One class declares a field, and the other references the field in some way.”

class A { boolean f; } class B { void m() { new A().f = true; } } class A { int f; class B { void m() { int i = f; } } }

...

slide-18
SLIDE 18

18

class A { int f; } class B extends A { void m() { super.f = 0; } }

Example Generator

“Produces pairs of classes related by containment and inheritance. One class declares a field, and the other references the field in some way.”

class A { boolean f; } class B { void m() { new A().f = true; } } class A { int f; class B { void m() { int i = f; } } }

...

slide-19
SLIDE 19

19

class A { int f; } class B extends A { void m() { super.f = 0; } }

Example Generator

“Produces pairs of classes related by containment and inheritance. One class declares a field, and the other references the field in some way.”

class A { boolean f; } class B { void m() { new A().f = true; } } class A { int f; class B { void m() { int i = f; } } }

...

slide-20
SLIDE 20

20

class A { int f; } class B extends A { void m() { super.f = 0; } }

Example Generator

“Produces pairs of classes related by containment and inheritance. One class declares a field, and the other references the field in some way.”

class A { boolean f; } class B { void m() { new A().f = true; } } class A { int f; class B { void m() { int i = f; } } }

...

slide-21
SLIDE 21

21

Composing Generators

×

class A { class B {} } class A {} class B {} class A { void m() { class B {} } } ... class A {} class B {} class A {} class B extends A {} ... int f; boolean f; public char f; ... f this.f this.A.f new A().f super.f ...

Containment Generator Inheritance Generator Field Declaration Generator Field Reference Generator

× ×

slide-22
SLIDE 22

22

  • Composition may be invalid
  • Three solutions

– T

ester writes filter that verifies values

– Dependent generators – Delegate to compiler

Invalid Combinations

int f; super.f

depends on

class A { class B {} } class A extends B {} class B {}

+

class A extends B { class B {} }

=

slide-23
SLIDE 23

23

Oracles

  • Check that the program was refactored

correctly

  • Challenges

– Don't know expected output – Semantic equivalence is undecidable – Need to verify that correct structural changes

were made

slide-24
SLIDE 24

24

Oracles

  • DoesCrash

– Engine throws exception

  • DoesNotCompile (DNC)

– Refactored program does not compile

  • WarningStatus (WS)

– Engine cannot perform refactoring – Presence or lack of WarningStatus may

indicate bug

slide-25
SLIDE 25

25

Oracles

  • Inverse (I)

– Refactorings are invertible – Check that a refactoring is undone by its

inverse

– ASTComparator: Compares normalized AST

s

  • Custom (C)

– Check for desired structural changes

  • Differential (Diff)

– Perform refactoring in both Eclipse and

NetBeans

slide-26
SLIDE 26

26

Case Study

  • T

ested Eclipse and NetBeans

  • Eight refactorings

– T

arget field, method, or class

  • Wrote about 50 generators
  • Reported 47 new bugs
  • Compared effectiveness of oracles
slide-27
SLIDE 27

27

Generator Evaluation

  • Generation and compilation time less

than refactoring time and oracles

  • Human time: T
  • ok about two workdays to

produce MethodReference

– Reused many generators

Bugs Refactoring Generator Inputs NB 72 0:45 1 1512 15:19 4 3 3969 41:45 1 2 48 1:16 1 417 8:45 3 3 Rename(Class) 88 1:02 Rename(Method) 9540 89:12 Rename(Field) 1512 28:20 1 Rename(Field) 3969 76:55 ... ... ... ... ... ... Total 21 26 Time (m:ss) Ecl EncapsulateField ClassArrayField FieldReference DoubleClassFieldRef. SingleClassTwoFields DoubleClassGetterSetter ClassRelationships MethodReference FieldReference DoubleClassFIeldRef.

slide-28
SLIDE 28

28

Oracle Evaluation

  • DoesNotCompile found the most bugs
  • WarningStatus, Inverse, and Differential

can give false positives

  • Many input programs exhibit same bug

WS DNC C/I Bugs Refactoring Generator NB NB NB 48 48 1 320 432 14 121 4 3 187 256 100 511 1 2 48 15 1 216 162 162 18 216 3 3 Rename(Class) Rename(Method) Rename(Field) 304 40 1 Rename(Field) ... ... ... ... ... ... ... ... Total 21 26 Diff Ecl Ecl Ecl EncapsulateField ClassArrayField FieldReference DoubleClassFieldRef SingleClassTwoFields DoubleClassGetterSetter ClassRelationships MethodReference FieldReference DoubleClassFieldRef.

slide-29
SLIDE 29

29

Results

  • 47 new bugs reported

– 21 in Eclipse: 20 confirmed by developers – 26 in NetBeans: 17 confirmed, 3 fixed, 5

duplicates, 1 won't fix

– Found others, but did not report duplicate or

fixed

  • Currently working with NetBeans

developers to include ASTGen in testing process

slide-30
SLIDE 30

30

Related Work

  • Grammar-based test data generation

P . Purdom 1972

P . M. Maurer 1990

  • E. G. Sirer and B. N. Bershad 1999

  • B. A. Malloy and J. F

. Power 2001

  • Declarative, bounded-exhaustive

generation

  • C. Boyapati, S. Khurshid, and D. Marinov 2002

  • S. Khurshid and D. Marinov 2004

  • R. Lämmel and W. Schulte 2006
  • QuickCheck

  • K. Claessen and J. Hughes 2000
slide-31
SLIDE 31

31

Future Work

  • More refactorings
  • Apply ASTGen to other program analyzers
  • Removal of redundant tests, bug

targeting

  • Reduce or eliminate false alarms

– Improved AST Comparator

slide-32
SLIDE 32

32

Conclusions

  • Despite their popularity, refactoring

engines contain bugs

  • ASTGen allows one to create many

interesting AST s

  • We reported 47 new bugs

http://mir.cs.uiuc.edu/astgen/

slide-33
SLIDE 33

Imperative vs. Declarative

  • How to produce data

vs. What data should look like

  • TODO
slide-34
SLIDE 34

34

Refactorings are behavior- preserving program transformations that improve the design of a program