272: Software Engineering Fall 2012 Instructor: Tevfik Bultan Lecture 6: Exhaustive Bounded Testing and Feedback-Directed Random Testing.

Slides:



Advertisements
Similar presentations
Chapter 22 Implementing lists: linked implementations.
Advertisements

Chapter 23 Organizing list implementations. This chapter discusses n The notion of an iterator. n The standard Java library interface Collection, and.
Copyright © 2006 The McGraw-Hill Companies, Inc. Programming Languages 2nd edition Tucker and Noonan Chapter 18 Program Correctness To treat programming.
Rigorous Software Development CSCI-GA Instructor: Thomas Wies Spring 2012 Lecture 7.
Author: Carlos Pacheco, Shuvendu K. Lahiri, Michael D. Ernst, Thomas Ball MIT CSAIL.
Korat Automated Testing Based on Java Predicates Chandrasekhar Boyapati, Sarfraz Khurshid, Darko Marinov MIT ISSTA 2002 Rome, Italy.
Semantics Static semantics Dynamic semantics attribute grammars
CS 267: Automated Verification Lecture 8: Automata Theoretic Model Checking Instructor: Tevfik Bultan.
Abstraction and Modular Reasoning for the Verification of Software Corina Pasareanu NASA Ames Research Center.
1 Symbolic Execution for Model Checking and Testing Corina Păsăreanu (Kestrel) Joint work with Sarfraz Khurshid (MIT) and Willem Visser (RIACS)
1/20 Generalized Symbolic Execution for Model Checking and Testing Charngki PSWLAB Generalized Symbolic Execution for Model Checking and Testing.
Composition CMSC 202. Code Reuse Effective software development relies on reusing existing code. Code reuse must be more than just copying code and changing.
Data Abstraction II SWE 619 Software Construction Last Modified, Spring 2009 Paul Ammann.
JMLAutoTest and Its Double- phase Testing Way Guoqing Xu Com Sci., East China Normal Univ. Shanghai , PRC FATES 2003, Montreal, Canada, Oct.6th 2003.
Rigorous Software Development CSCI-GA Instructor: Thomas Wies Spring 2012 Lecture 13.
CS 267: Automated Verification Lecture 10: Nested Depth First Search, Counter- Example Generation Revisited, Bit-State Hashing, On-The-Fly Model Checking.
Feedback-Directed Random Test Generation Automatic Testing & Validation CSI5118 By Wan Bo.
CS 290C: Formal Models for Web Software Lecture 10: Language Based Modeling and Analysis of Navigation Errors Instructor: Tevfik Bultan.
272: Software Engineering Fall 2008 Instructor: Tevfik Bultan Lecture 10: Testing, Automated Testing.
1 Today Another approach to “coverage” Cover “everything” – within a well-defined, feasible limit Bounded Exhaustive Testing.
Chapter 1 Principles of Programming and Software Engineering.
Efficient Software Model Checking of Data Structure Properties Paul T. Darga Chandrasekhar Boyapati The University of Michigan.
Efficient Modular Glass Box Software Model Checking Michael Roberson Chandrasekhar Boyapati The University of Michigan.
CS 267: Automated Verification Lecture 13: Bounded Model Checking Instructor: Tevfik Bultan.
1/23/2003University of Virginia1 Korat: Automated Testing Based on Java Predicates CS751 Presentation by Radu Stoleru C.Boyapaty, S.Khurshid, D.Marinov.
272: Software Engineering Fall 2012 Instructor: Tevfik Bultan Lecture 8: Semi-automated test generation via UDITA.
Korat: Automated Testing Based on Java Predicates Chandrasekhar Boyapati 1, Sarfraz Khurshid 2, and Darko Marinov 3 1 University of Michigan Ann Arbor.
272: Software Engineering Fall 2012 Instructor: Tevfik Bultan Lecture 4: SMT-based Bounded Model Checking of Concurrent Software.
Software Testing Sudipto Ghosh CS 406 Fall 99 November 9, 1999.
272: Software Engineering Fall 2012 Instructor: Tevfik Bultan Lecture 17: Code Mining.
Feed Back Directed Random Test Generation Carlos Pacheco1, Shuvendu K. Lahiri2, Michael D. Ernst1, and Thomas Ball2 1MIT CSAIL, 2Microsoft Research Presented.
Software Engineering Prof. Dr. Bertrand Meyer March 2007 – June 2007 Chair of Software Engineering Static program checking and verification Slides: Based.
Korat: Automated Testing Based on Java Predicates
1 Debugging and Testing Overview Defensive Programming The goal is to prevent failures Debugging The goal is to find cause of failures and fix it Testing.
AITI Lecture 20 Trees, Binary Search Trees Adapted from MIT Course 1.00 Spring 2003 Lecture 28 and Tutorial Note 10 (Teachers: Please do not erase the.
Object-Oriented Program Development Using Java: A Class-Centered Approach, Enhanced Edition.
Low-Level Detailed Design SAD (Soft Arch Design) Mid-level Detailed Design Low-Level Detailed Design Design Finalization Design Document.
Chapter 18 Java Collections Framework
Today’s Agenda  HW #1  Finish Introduction  Input Space Partitioning Software Testing and Maintenance 1.
Software Testing Input Space Partition Testing. 2 Input Space Coverage Four Structures for Modeling Software Graphs Logic Input Space Syntax Use cases.
Topic 1 Object Oriented Programming. 1-2 Objectives To review the concepts and terminology of object-oriented programming To discuss some features of.
(c) University of Washington15-1 CSC 143 Java List Implementation via Arrays Reading: 13.
Dynamic Data Structures and Generics Chapter 10. Outline Vectors Linked Data Structures Introduction to Generics.
1 CSCD 326 Data Structures I Software Design. 2 The Software Life Cycle 1. Specification 2. Design 3. Risk Analysis 4. Verification 5. Coding 6. Testing.
ECSE Software Engineering 1I HO 4 © HY 2012 Lecture 4 Formal Methods A Library System Specification (Continued) From Specification to Design.
CSS446 Spring 2014 Nan Wang.  To understand the implementation of linked lists and array lists  To analyze the efficiency of fundamental operations.
Finding Errors in.NET with Feedback-Directed Random Testing Carlos Pacheco (MIT) Shuvendu Lahiri (Microsoft) Thomas Ball (Microsoft) July 22, 2008.
Directed Random Testing Evaluation. FDRT evaluation: high-level – Evaluate coverage and error-detection ability large, real, and stable libraries tot.
© 2006 Pearson Addison-Wesley. All rights reserved 2-1 Chapter 2 Principles of Programming & Software Engineering.
CS305j Introduction to Computing Classes II 1 Topic 24 Classes Part II "Object-oriented programming as it emerged in Simula 67 allows software structure.
PROGRAMMING TESTING B MODULE 2: SOFTWARE SYSTEMS 22 NOVEMBER 2013.
PROGRAMMING PRE- AND POSTCONDITIONS, INVARIANTS AND METHOD CONTRACTS B MODULE 2: SOFTWARE SYSTEMS 13 NOVEMBER 2013.
Automated Test Generation CS Outline Previously: Random testing (Fuzzing) – Security, mobile apps, concurrency Systematic testing: Korat – Linked.
Slides prepared by Rose Williams, Binghamton University Chapter 16 Collections and Iterators.
/ PSWLAB Evidence-Based Analysis and Inferring Preconditions for Bug Detection By D. Brand, M. Buss, V. C. Sreedhar published in ICSM 2007.
CIS 540 Principles of Embedded Computation Spring Instructor: Rajeev Alur
Object Design More Design Patterns Object Constraint Language Object Design Specifying Interfaces Review Exam 2 CEN 4010 Class 18 – 11/03.
Random Test Generation of Unit Tests: Randoop Experience
Symstra: A Framework for Generating Object-Oriented Unit Tests using Symbolic Execution Tao Xie, Darko Marinov, Wolfram Schulte, and David Notkin University.
Input Space Partition Testing CS 4501 / 6501 Software Testing
Principles of Programming and Software Engineering
Dynamic Symbolic Data Structure Repair
Programming Languages 2nd edition Tucker and Noonan
Hoare-style program verification
50.530: Software Engineering
Java Modeling Language (JML)
Assertions References: internet notes; Bertrand Meyer, Object-Oriented Software Construction; 4/25/2019.
Programming Languages 2nd edition Tucker and Noonan
Automated Test Generation
Presentation transcript:

272: Software Engineering Fall 2012 Instructor: Tevfik Bultan Lecture 6: Exhaustive Bounded Testing and Feedback-Directed Random Testing

Automated Testing Automated testing refers to the techniques which generate the test sets automatically We will talk about several automated testing techniques We will start with Korat Korat is also a kind of functional (black-box) testing tool –Requires the user to write a specification as a method in the class that is being testing It is used for unit testing –Especially for testing of complex data structure implementations It automatically generates test cases from specifications –It exhaustively generates all non-isomorphic test cases within a given scope

Korat An automated testing tool –Application domain is unit testing of complex data structures It uses Java predicates to generate the test cases –These are Java methods which return a boolean value –For example, pre and post-conditions of methods Korat generates the test cases from pre and postconditions of methods There is no need to write an extra specification if the class contract is written as Java predicates

Korat Korat uses the method precondition to automatically generate all nonisomorphic test cases up to a given small size –Given a predicate and a bound on the size of its inputs Korat generates all nonisomorphic inputs for which the predicate returns true Korat then executes the method on each test case and uses the method postcondition as a test oracle to check the correctness of output –Korat exhaustively explores the bounded input space of the predicate but does so efficiently by monitoring the predicate’s executions and pruning large portions of the search space

An Example: Binary Tree import java.util.*; class BinaryTree { private Node root; private int size; static class Node { private Node left; private Node right; } public boolean repOk() { // this method checks the class invariant: // checks that empty tree has size zero // checks that the tree has no cycle // checks that the number of nodes in the tree is // equal to its size }

An Example: Binary Tree public boolean repOk() { // checks that empty tree has size zero if (root == null) return size == 0; Set visited = new HashSet(); visited.add(root); LinkedList workList = new LinkedList(); workList.add(root); while (!workList.isEmpty()) { Node current = (Node)workList.removeFirst(); if (current.left != null) { // checks that tree has no cycle if (!visited.add(current.left)) return false; workList.add(current.left); } if (current.right != null) { // checks that tree has no cycle if (!visited.add(current.right)) return false; workList.add(current.right); } } // checks that size is consistent if (visited.size() != size) return false; return true; }

Finitization Korat uses a finitization description to specify the finite bounds on the inputs (scope) public static Finitization finBinaryTree(int NUM_node){ Finitization f = new Finitization(BinaryTree.class); ObjSet nodes = f.createObjects( “ Node ”, NUM_node); nodes.add(null); f.set( “ root ”, nodes); f.set( “ size ”, NUM_node); f.set( “ Node.left ”, nodes); f.set( “ Node.right ”, nodes); return f; } Korat automatically generates a finitization skeleton based on the type declarations in the Java code –Developers can restrict or extend this default finitization Creates a set of objects of Type “ Node ” with NUM_node objects in the set The value of size is set to NUM_node

Non-isomorphic Instances for finBinaryTree(3) N0 N1 N2 N0 N1 N2 N0 N1 N2 N0 N1 N2 N0 N1N2 right left right left right left Korat automatically generates non-isomorphic instances within a given bound For finBinaryTree(3) Korat generates the 5 non-isomorphic trees shown above. Each of the above trees correspond to 6 isomorphic trees. Korat only generates one tree representing the 6 isomorphic trees. For finBinaryTree(7) Korat generates 429 non-isomorphic trees in less than a second

Isomorphic Instances N0 N1N2 right left N0 N2N1 right left N1 N2N0 right left N1 N0N2 right left N2 N1N0 right left N2 N0N1 right left

How many Instances are There? How many instances are there? What is the size of the state space? Consider the binary tree example with scope 3 –There are three fields: root, left, right –Each of these fields can be assigned a node instance or null –There is one root field and there is one left and one right field for each node instance We can consider each test case for the binary tree with scope 3 a vector with 8 values –The value of the root (has 4 possible values, null or a node object) –The value of the size (has only one possible value, which is 3) –For each node object (there are three of them) The value of the left field (4 possible values) The value of the right field (4 possible values) State space : 4  1  (4  4) 3

How many Instances are There? Given n node instances, the state space (the set of all possible test cases) for the binary tree example is: (n+1) 2n + 1 Most of these structures are not valid binary trees –They do not satisfy the class invariant Most of these structures are isomorphic –they are equivalent if we ignore the object identities

Generating test cases The challenge is generating all the non-isomorphic test cases that satisfy the class invariant 1.Korat only generates non-isomorphic test cases 2.Korat prunes the state space by eliminating sets of test cases which do not satisfy the class invariant

Isomorphism In Korat isomorphism is defined with respect to a root object –for example this Two test cases are defined to be isomorphic if the parts of their object graphs reachable from the root object are isomorphic The isomorphism definition partitions the state space (i.e. the input domain) to a set of isomorphism partitions –Korat generates only one test case for each partition class

Isomorphism The isomorphism definition used in Korat is the following –O 1, O 2,..., O n are sets objects from n classes –O = O 1  O 2 ...  O n –P: the set consisting of null and all values of primitive types that the fields of objects in O can contain –r  O is a special root object –Given a test case C, O C is the set of objects reachable from r in C Two test cases C and C’ are isomorphic iff there is a permutation  on O, mapping objects from O i to objects from O i for all 1  i  n, such that  o, o’  O C.  f  fields(o).  p  P. o.f == o’ in C iff  (o).f ==  (o’) in C’ and o.f == p in C iff  (o).f == p in C’

Generating Test Cases Korat only generates the test cases which satisfies the input predicate: class invariant and the precondition Korat explores the state space efficiently using backtracking –It does not generate all instances one by one and check the input predicate –It prunes its search of the state space based on the evaluation of the input predicate If the method that checks the input predicate returns false without checking a field then there is no need to generate test cases which assign different values to that field –In order to exploit this, Korat keeps track of the fields that are accessed before the predicate returns false –For this to work well, predicate method should return false as soon as it detects a violation

Generating Test Cases Korat orders all the elements in every class domain and every field domain Each test case is represented as a vector of indices into the corresponding field domains N0 N1N2 right left size=3 [1,0,2,3,0,0,0,0,] Test CaseCorresponding Vector For the Binary Tree example assume that: The class domain is ordered as N0 < N1 < N2 The field domains for root, left and right are ordered as null < N0 < N1 < N2 (with indices 0, 1, 2, 3) The size domain has one element which is 3 (with index 0) [1,0,2,3,0,0,0,0,] fields of the Binary tree object fields of the Node object N0 fields of the Node object N1 fields of the Node object N2

Generating Test Cases Search starts with a candidate vector set to all zeros. For each candidate vector, Korat sets fields in the objects according to the values in the vector. Korat then invokes repOk (i.e., class invariant) to check the validity of the current candidate. –During the execution of repOk, Korat monitors the fields that repOK accesses, it stores the indices of the fields that are accessed by the repOK (field ordering) –For example, for the binary tree example, if the repOK accesses root, N0.left and N0.right, then the field ordering is 0, 2, 3 Korat generates the next candidate vector by backtracking on the fields accessed by repOk. –First increments the field domain index for the field that is last in the field-ordering –If the field index exceeds the domain size, then Korat resets that index to zero and increments the domain index of the previous field in the field ordering

Generating Test Cases Korat achieves non-isomorphic test case generation using the ordering of field domains and the vector representation While generating the test cases, Korat ensures that the indices of the objects that belong to the same class domain are listed in nondecreasing order in the generated candidate vectors This means that during backtracking, Korat looks for fields –that precede the field that is accessed last and –that have an object from the same class domain as the field that is accessed last –and makes sure that the object assigned to the field that is accessed last is higher in the ordering than those objects

Using Contracts in Testing Korat checks the contracts written in JML on the generated instances public invariant repOk(); //class invariant requires has(n) // ensures !has(n)// public void remove(Node n) {... } JML (Java Modeling Language) is an annotation language for writing contracts (pre, post-conditions for methods, class invariants) for Java classes in the style of Design-by-Contract Korat uses JML tool-set to translate JML annotations into runtime Java assertions

Using Contracts in Testing Given a finitization, Korat generates all non-isomorphic test cases within the given scope (defined by the finitization) that satisfy the class invariant and the pre-condition The post-conditions and class invariants provide a test oracle for testing –For each generated test case, execute the method that is being tested and check the class invariant and the post-condition Korat uses JML tool-set to automatically generate test oracles from method post-conditions written as annotations in JML

Korat Performance Checking a BinaryTree implementation –with scope 8 takes 1/53 seconds, –with scope 11 takes seconds, –with scope 12 takes seconds. Test case generation with Korat is more efficient than a previous approach that used SAT solvers for generating test cases

Small Scope Hypothesis Success of Korat depends on the small scope hypothesis Small scope hypothesis –If there is a bug, there is typically a counter-example demonstrating the bug within a small scope. This is not a bad assumption if you are analyzing data structures (the target for Korat)

Random Testing We discussed that random testing is hopeless is one uses a uniform distribution for inputs –The chances of covering a particular condition is very low However, if we use the program being tested to guide how we choose the test cases than random test generation can be more effective –Construct the inputs using the methods that are part of the program that is being tested This is the approach used in feedback-directed random test generation

Feedback-Directed Random Unit Testing This is a unit testing approach where it is assumed that the unit under test consists of a set of methods –A class, or a set of classes in an object oriented program for example The basic idea is to build inputs incrementally by randomly selecting a method call to apply and finding arguments from among previously constructed inputs –The result (object) returned by the newly generated call is first checked against Contracts (to look for contract violations) Filters (to eliminate duplicate or uninteresting cases) –Then it is added to the available set of inputs to be used as an input in future method calls

Randoop Randoop is a fully automated testing tool that implements the feedback-directed random test generation for.NET and Java An object-oriented unit test consists of a sequence of method calls that set up the state (by creating and mutating objects) and an assertion about the result of the final call –Randoop generates such unit tests Randoop found serious errors in widely-deployed commercial open- source software

Method Sequences A method sequence is a sequence of method calls: A a1 = new A(); B b3 = a1.m1(a1); Each call in the sequence includes a method name and input arguments, which can be –Primitive values such as 0, true, null, or –Objects returned by previous calls –The receiver of the method call is treated as the first argument of the method call A method sequence can be written as code and executed

Extending sequences Randoop uses an incremental approach to test generation –It generates method sequences by extending sequences by one method call at a time It uses an extension operation that takes zero or more sequences as input and generates a new sequence extend(m, seqs, vals) –m is a method with formal parameters (including the receiver) of type T 1, T 2, …, T k –seqs is a list of sequences (possibly empty) –vals is a list of values v 1 : T 1, v 2 :T 2, … v k :T k Each value is a primitive value or it is the return value s.i of the i-th method call for a sequence s appearing in seqs The result of extend(m, seqs, vals) is a new sequence that is the concatenation of the input sequences seqs in the order that they appeared, followed by the method call m(v 1, v 2, …, v k )

Generating sequences GenerateSequences algorithm takes a set of classes, contracts, filters and timeLimit as input It starts from an empty set of sequences –Builds sequences incrementally by extending previous sequences As soon as a sequence is built, it executes it to ensure that it creates a non-redundant and legal objects, as specified by filters and contracts

Algorithm for generating method sequences GenreateSequences(classes, contracts, filters, timeLimit) errorSeqs := {} nonErrorSeqs := {} while timeLimit not reached do m(T 1,T 2, …, T k ) := randomPublicMethod(classes) := randomSeqsAndVals(nonErrorSeqs, T 1,T 2, …, T k ) neqSeq := extend(m, seqs, vals) if newSeq  nonErrorSeqs  errorSeqs then continue endif := execute(newSeq, contracts) if violated = true then errorSeqs := errorSeqs  {newSeq} else nonErrorSeqs : = nonErrorSeqs  {newSeq} setExtensibleFlags(neqSeq, filters, o) endif endwhile return

Random selection of sequences and values The function randomSeqsAndVals(nonErrorSeqs, T 1,T 2, …, T k ) incrementally builds a list of sequences seqs and a list of values vals At each step it adds a value to vals and potentially also a sequence to seqs For each input argument type T i it does the following –If it is a primitive type pick a value from a fixed pool of values In the implementation they use a small primitive pool that can be augmented by the user or other tools –If it is an object, they pick one of the following three possibilities randomly: 1.Use a value v from a sequences that is already in seqs 2.Add a sequence from nonErrorSeqs to seqs and use a value from it 3.Use null –When using a value produced by an existing sequence, the value must be extensible (v.extensible = true)

Filtering to identify extensible values Filtering determines which values are extensible (i.e., can be used to extend a sequence after they are created) Each sequence has an associated boolean vector: –Each value s.i (the value returned by the ith method call in the sequence) has a boolean flag s.i.extensible s.i.extensible indicates whether the given value may be used as an input to a new method call –This is used to prune the state space Extensible flag is set to false if the value is considered redundant or illegal for the purpose of creating a new sequence –Assume that the s.i corresponds to the object o, then s.i.extensible is set to false if there exists another extensible object o’ that was created earlier and o.equals(o’) returns true –If the s.i is null, then s.i.extensible is set to false –If s.i throws an exception, then s.i.extensible is set to false since exceptions typically correspond to a violation

Evaluation They compared Randoop with an exhaustive bounded testing approach that uses JPF –They focused on container classes (BinTree, Bheap, FibHeap) –Randoop achieved better coverage in shorter amount of time They used Randoop to check API contracts in 14 widely-used libraries (java.util, javax.xml, Jakarta Commons,.NET Framework) –JPF based exhaustive bounded testing does not scale to this type of testing –Randoop produced 4200 distinct violation inducing test cases –They developed a reduction technique to automatically reduce the reported violations (if two test cases cause the same violation, only report one) –After the reduction, they obtained 254 error-revealing test cases that pointed to 210 distinct errors

Errors Some discovered errors: Eight of the methods in the JDK create collections that return false on s.equals(s) In Jakarta –a hasCode implementation fails to handle a valid object configuration where a field is null –An iterator object throws a NullPointerException if initialized with zero elements In.NET libraries –155 errors are NullReferenceExceptions in the absence of null inputs –21 are IndexOutOfRangeExceptions –20 are violations of equals, hashCode and toString contracts