tutorial nikolai tillmann, peli de halleux, wolfram schulte (microsoft research) tao xie (north...

104
Parameterized Unit Testing: Principles, Techniques, and Applications in Practice Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Post on 21-Dec-2015

215 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Parameterized Unit Testing:Principles, Techniques, and Applications in Practice

Tutorial

Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research)

Tao Xie (North Carolina State University)

Page 2: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Outline

Unit Testing Parameterized Unit Testing Input Generation with Pex Patterns for Parameterized Unit

Testing Parameterized Models Wrapping up

Page 3: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

About the tool…

We will use the tool Pex as part of the exercises To install it, you need

Windows XP or Vista .NET 2.0

Download Pex fromhttp://research.microsoft.com/en-us/projects/pex/downloads.aspx

Two variations : pex.devlabs.msi:

requires Visual Studio 2008 Team System pex.academic.msi:

does not require Visual Studio, but for non-commercial use only

To run the samples, you need VS Team System

Page 4: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Unit TestingIntroduction

Page 5: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Unit Testing

void ReadWrite() { var list = new List(); list.Add(3); Assert.AreEqual(1, list.Count);}

A unit test is a small program with assertions Test a single (small) unit of code

Page 6: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Unit Testing Good/Bad

Design and specification By Example Documentation Short feedback loop Code coverage and regression testing Extensive tool support for test execution and

management

Happy path only Hidden integration tests

Touch the database, web services, requires multiple machines, etc…

New Code with Old Tests Redundant tests

Page 7: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Unit Testing: Measuring Quality

Coverage: Are all parts of the program exercised? statements basic blocks explicit/implicit branches …

Assertions: Does the program do the right thing? test oracle

Experience: Just high coverage of large number of assertions

is no good quality indicator. Only both together are!

Page 8: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Exercise: “TrimEnd”Unit TestingGoal: Implement and test TrimEnd:

Open Visual Studio Create CodeUnderTestProject, and implement TrimEnd

File -> New -> Project -> Visual C# -> Class Library Add new StringExtensions class Implement TrimEnd

Create TestProject, and test TrimEnd File -> New -> Project -> C# -> Test -> Test Project Delete ManualTest.mht, UnitTest1.cs, … Add new StringExtensionsTest class Implement TrimEndTest

Execute test Test -> Windows -> Test View, execute test, setup and inspect Code

Coverage

// trims occurences of the ‘suffix’ from ‘target’string TrimEnd(string target, string suffix);

Page 9: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Exercise: “TrimEnd”Unit Testingpublic class StringExtensions { public static string TrimEnd(string target, string suffix) { if (target.EndsWith(suffix)) target = target.Substring(0, target.Length-suffix.Length); return target; }}[TestClass]public class StringExtensionTest { [TestMethod] public void TrimEndTest() { var target = "Hello World"; var suffix = "World"; var result = StringExtensions.TrimEnd(target, suffix); Assert.IsTrue(result == "Hello "); }}

Page 10: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Parameterized Unit TestingIntroduction

Page 11: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

The Recipe of Unit Testing

var list = new List(); list.Add(item); var count = list.Count;

Assert.AreEqual(1, count);}

Three essential ingredients: Data Method Sequence Assertionsvoid Add() { int item = 3;

Page 12: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

The (problem with) Data

Which value matters? Bad choices cause redundant, or worse,

incomplete test suites. Hard-coded values get stale when

product changes. Why pick a value if it doesn’t matter?

list.Add(3);

Page 13: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Parameterized Unit Testing

void Add(List list, int item) { var count = list.Count; list.Add(item); Assert.AreEqual(count + 1, list.Count);}

Parameterized Unit Test = Unit Test with Parameters

Separation of concerns Data is generated by a tool Developer can focus on functional

specification

Page 14: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Parameterized Unit Tests areAlgebraic Specifications

A Parameterized Unit Test can be read as a universally quantified, conditional axiom.void ReadWrite(string name, string data) { Assume.IsTrue(name != null && data != null); Write(name, data); var readData = Read(name); Assert.AreEqual(data, readData);} string name, string data: name ≠ null data ≠ null ⋀ ⇒ equals( ReadResource(name,WriteResource(name,data)), data)

Page 15: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Parameterized Unit Testingis going mainstreamParameterized Unit Tests (PUTs) commonly

supported by various test frameworks .NET: Supported by .NET test frameworks

http://www.mbunit.com/ http://www.nunit.org/ …

Java: Supported by JUnit 4.X http://www.junit.org/

Generating test inputs for PUTs supported by tools .NET: Supported by Microsoft Research Pex

http://research.microsoft.com/Pex/ Java: Supported by Agitar AgitarOne

http://www.agitar.com/

Page 16: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Exercise: “TrimEnd”Manual Parameterized Unit Testing

Goal: Create a parameterized unit test for TrimEnd..

Refactor: Extract Method[TestMethod]public void TrimEndTest() { var target = "Hello World"; var suffix = "World"; var result = ParameterizedTest(target, suffix); Assert.IsTrue(result == "Hello ");}

static string ParameterizedTest(string target, string suffix) { var result = StringExtensions.TrimEnd(target, suffix); return result;}

Page 17: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

17

Goal: Given a program with a set of input parameters, automatically generate a set of input values that, upon execution, will exercise as many statements as possible

Observations: Reachability not decidable, but

approximations often good enough Encoding of functional correctness checks

as assertions that reach an error statement on failure

Data Generation Challenge

Page 18: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Assumptions and Assertions

void PexAssume.IsTrue(bool c) { if (!c) throw new AssumptionViolationException();}void PexAssert.IsTrue(bool c) { if (!c) throw new AssertionViolationException();}

Assumptions and assertions induce branches

Executions which cause assumption violations are ignored, not reported as errors or test cases

Page 19: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Data Generation

Human Expensive, incomplete, …

Brute Force Pairwise, predefined data, etc…

Semi - Random: QuickCheck Cheap, Fast “It passed a thousand tests” feeling

Dynamic Symbolic Execution: Pex, Cute,EXE Automated white-box Not random – Constraint Solving

Page 20: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Dynamic Symbolic Execution

Code to generate inputs for:

Constraints to solve

a!=null a!=null &&a.Length>0

a!=null &&a.Length>0 &&a[0]==1234567890

void CoverMe(int[] a){ if (a == null) return; if (a.Length > 0) if (a[0] == 1234567890) throw new Exception("bug");}

Observed constraints

a==nulla!=null &&!(a.Length>0)a!=null &&a.Length>0 &&a[0]!=1234567890

a!=null &&a.Length>0 &&a[0]==1234567890

Data

null

{}

{0}

{123…}a==null

a.Length>0

a[0]==123…T

TF

T

F

F

Execute&MonitorSolve

Choose next path

Done: There is no path left.

Negated condition

Page 21: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Exercise: “CoverMe”Dynamic Symbolic Execution with Pex Open CoverMe project in Visual Studio. Right-click on CoverMe method, and select

“Run Pex”. Inspect results in table.

public static void CoverMe(int[] a){ if (a == null) return; if (a.Length > 0) if (a[0] == 1234567890) throw new Exception("bug");}

Page 22: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

How to test this code?(Actual code from .NET base class libraries)

Motivation: Unit Testing HellResourceReader

Page 23: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Motivation: Unit Testing HellResourceReader

Page 24: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Exercise: “ResourceReaderTest”ResourceReader[PexClass, TestClass]

[PexAllowedException(typeof(ArgumentNullException))][PexAllowedException(typeof(ArgumentException))][PexAllowedException(typeof(FormatException))][PexAllowedException(typeof(BadImageFormatException))][PexAllowedException(typeof(IOException))][PexAllowedException(typeof(NotSupportedException))]public partial class ResourceReaderTest { [PexMethod] public unsafe void ReadEntries(byte[] data) { PexAssume.IsTrue(data != null); fixed (byte* p = data) using (var stream = new UnmanagedMemoryStream(p, data.Length)) { var reader = new ResourceReader(stream); foreach (var entry in reader) { /* reading entries */ } } }}

Page 25: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

When does a test case fail? If the test does not throw an exception, it

succeeds. If the test throws an exception,

(assumption violations are filtered out), assertion violations are failures, for all other exception, it depends on further

annotations.

Annotations Short form of common try-catch-assert test code [PexAllowedException(typeof(T))] [PexExpectedException(typeof(T))]

Page 26: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Dynamic Symbolic ExecutionPex Architecture

A brief overview

Page 27: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Code Instrumentation

Z3

Pex

ExtendedReflection

Instrumentation framework “Extended Reflection” Instruments .NET code at runtime Precise data flow and control flow analysis

Code Under Test

Page 28: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Dynamic Symbolic Execution

Z3

Pex

ExtendedReflection

Pex listens to monitoring callbacks Symbolic execution along concrete

execution

Code Under Test

Page 29: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Constraint Solving

Z3

Pex

ExtendedReflection

Constraint solving with SMT solver Z3 Computes concrete test inputs

Code Under Test

Page 30: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Test Generation

Z3

Pex

ExtendedReflection

Execute with test inputs from constraint solver Emit test as source code if it increases

coverage

Code Under Test

Page 31: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Components

Z3

Pex

ExtendedReflection

ExtendedReflection: Code Instrumentation Z3: SMT constraint solver Pex: Dynamic Symbolic Execution

Code Under Test

Page 32: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

ldtoken Point::GetXcall __Monitor::EnterMethodbrfalse L0ldarg.0call __Monitor::Argument<Point>

L0: .try { .try { call __Monitor::LDARG_0 ldarg.0 call __Monitor::LDNULL ldnull call __Monitor::CEQ ceq call __Monitor::BRTRUE brtrue L1 call __Monitor::BranchFallthrough call __Monitor::LDARG_0 ldarg.0 …

ldtoken Point::X call __Monitor::LDFLD_REFERENCE ldfld Point::X call__Monitor::AtDereferenceFallthrough br L2

L1: call __Monitor::AtBranchTarget call __Monitor::LDC_I4_M1 ldc.i4.m1

L2: call __Monitor::RET stloc.0 leave L4 } catch NullReferenceException {

‘ call__Monitor::AtNullReferenceException rethrow }

L4: leave L5} finally { call __Monitor::LeaveMethod endfinally }

L5: ldloc.0ret

class Point { int x; static int GetX(Point p) { if (p != null) return p.X; else return -1; } }

Prologue

Epilogue

Calls will performsymbolic computation

Calls to build path condition

Calls to build path condition

Record concrete values to have all information

when this method is calledwith no proper context(The real C# compiler

output is actually more complicated.)

pp

null

p == null

Code Instrumentationby example

Page 33: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Pex’s representation of symbolic values and state is similar to the ones used to build verification conditions in ESC/Java, Spec#, …Terms for Primitive types (integers, floats, …), constants, expressions Struct types by tuples Instance fields of classes by mutable ”mapping of references

to values" Elements of arrays, memory accessed through unsafe

pointers by mutable “mapping of integers to values"

Efficiency by Many reduction rules, including reduction of ground terms to

constants Sharing of syntactically equal sub-terms BDDs over if-then-else terms to represent logical operations Patricia Trees to represent AC1 operators

(including parallel array updates)

Symbolic State Representation

Page 34: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

SMT-Solver (“Satisfiability Modulo Theories”) Decides logical first order formulas with respect to

theories SAT solver for Boolean structure Decision procedures for relevant theories:

uninterpreted functions with equalities,linear integer arithmetic, bitvector arithmetic, arrays, tuples

Model generation for satisfiable formulas Models used as test inputs

Limitations No decision procedure for floating point arithmetic

http://research.microsoft.com/z3

Constraint Solving: Z3

Page 35: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Pex inVisual StudioParameterized Unit Testing

Page 36: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Test Project

Test Generation WorkFlow

Code-Under-Test

Project

Parameterized Unit Tests

Pex Generated Tests

Page 37: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Right-click on the code-under-test project In the Solution Explorer

Select “Pex” Select “Create Parameterized Unit

Test Stubs”

Creating a (Parameterized)Test Project

Page 38: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

(Parameterized) Test Project

Generated Test ProjectReferencesMicrosoft.Pex.Framework(and more)

ReferencesVisualStudio UnitTestFramework

Contains source files with generated Parameterized Unit Test stubs

Page 39: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Right-click on Parameterized Unit Test For now, it just calls the implementation,

but the you should edit it, e.g. to add assertions

Select “Run Pex Explorations”

Running Pex from the Editor

Page 40: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Exploration Result View

Exploration

Status

Current Parameterize

d Unit Test

Issue barImportant messages here !!!

Input/Output tableRow = generated testColumn = parameterized test input or output

Page 41: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Input/Output table

Test outcomefiltering

PassingTest

Fix available

New Test

FailingTest

Page 42: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Input/Output table

ExceptionStack traceReview test

Allow exception

Page 43: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Pex Explorer

Pex Explorer makes it easy to digest the results of many Parameterized Unit Tests, and many generated test inputs

Page 44: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Pex from theCommand linepex.exe

Page 45: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Pex.exe test.dll

Page 46: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

HTML Reports

Rich information, used by Pex developers Full event log history Parameter

table Code

coverage etc…

HTML rendered from XML report file:It is easy to programmatically extract information!

Page 47: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Annotations: Code Under Test

Tell Pex which Type you are testing Code coverage Exception filtering Search prioritization

[PexClass(typeof(Foo))]public class FooTest { …

Page 48: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Code Coverage Reports

3 Domains UserCodeUnderTest

UserOrTestCode

SystemCode

public void CodeUnderTest() { … }

[PexClass] public class FooTest { [PexMethod] public void ParamTest(…) { …

public class String { public bool Contains(string value) { …

Page 49: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Command line: Filters

Namespace, type, method filters pex.exe test.dll /tf:Foo /mf:Bar

Partial match, case insensitive Full match: add “!”: /tf:Foo! Prefix: add “*”: /tf:Foo*

Many other filters e.g. to select a “suite”: /sf=checkin For more information:pex.exe help filtering

Page 50: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

ExerciseData generation

Goal: Explore input generation techniques with TrimEnd

Write or discuss a random input generator for TrimEnd

Adapt your parameterized unit tests for Pex Start over with “Create Parameterized Unit Test Stubs”,

or…▪ Add reference to Microsoft.Pex.Framework▪ Add using Microsoft.Pex.Framework;▪ Add [PexClass(typeof(StringExtensions))] on

StringExtensionsTest▪ Add [PexMethod] on your parameterized tests

Right-click in test and ‘Run Pex Explorations’ Compare test suites

Page 51: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

LimitationsIt’s called Parameterized Unit Testing

Page 52: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

The yellow event bar notifies about important events, including certain limitations

Event Bar

Click on issue kind for more information

Page 53: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Events View

You should act on these events: Refactor your code, or tell Pex to ignore it in the future, let Pex analyze (“instrument”) more code,

if possible.

Click on a particular event for more information

Understand the issue, and take an action

Page 54: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Instrumenting more code If Pex reports that some code was

uninstrumented, you may tell Pex to instrument and analyze it(if possible)

Page 55: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Instrumenting more code

Code instrumentation on Demand Instrumentation has high performance

overhead Some parts of the code better ignored

Use PexInstrument… attributes

Pex will often suggest and insert those attributes for you

[assembly: PexInstrumentAssembly(“Foo”)]

Page 56: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Pex understand managed .NET code only Pex does not understand native code.

Problem if branching over values obtained from the environment Pex may not automatically detect all such

cases.

Testability

if (!File.Exists(f)) throw ...

File System?

Page 57: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Hidden Complexity

Pex analyzes every executed .NET instruction

Some used libraries may be surprisingly expensive to analyze XML parsing repeatedly converting data between different

representationsvoid Sum(string[] A) { var sum = “0”; foreach(var a in A) sum = (int.Parse(a) + int.Parse(sum)).ToString(); if(sum == “123”) throw new Exception(); }

Don’t do this.

Page 58: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

There are decision procedures for individual path conditions, but… Number of potential paths grows

exponentially with number of branches Reachable code not known initially Without guidance, same loop might be

unfolded forever

Explosion of Search Space

Page 59: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Explosion of Search Space

To deal with the path explosion problem, Pex uses search heuristics.

Heuristics try to create “diversity”, i.e. they prefer paths which are so far underrepresented e.g. by their coverage vectors

Page 60: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Exploration Boundaries

In the presence of loops and recursion,Pex could search forever, so Pex has many ways to bound the search

Named arguments of [PexMethod]

Pex will often suggest and update those bounds for you.

[PexMethod(MaxConstraintSolverTime = 4)]

Page 61: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Exploration Boundaries

Configurable bounds include: TimeOut MaxBranches MaxCalls MaxConditions

▪ Number of conditions that depend on test inputs

MaxRuns ConstraintSolverTimeOut ConstraintSolverMemoryLimit

Page 62: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Division and modulo are expensive to reason about

No decision procedures for floating-point arithmetic Pex currently uses heuristic search

techniques for floating-point constraints

Constraint Solving

Page 63: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Constraint Solvingvs. Search Strategies

TestInputs

Constraint System

Execution Path

KnownPaths

Initially, choose ArbitraryPath-constraint

solving is just hard.

Reachability is

undecidable! (Loops)

(With external

functions and dynamic loading,

summariesare difficult.)

Page 64: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Multi-threaded code

Pex only explores single-threaded code

Related approach to explore thread-schedules (but not input parameters): CHESShttp://research.microsoft.com/en-us/projects/chess/

Page 65: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Lack of Test Oracle

Write assertions and Pex will try to break them

Without assertions, Pex can only find violations of runtime contracts causing NullReferenceException, IndexOutOfRangeException, etc.

Assertions leveraged in product and test code

Pex can leverage Code Contracts (discussed later)

Page 66: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Object Creation

Pex only uses public methods to configure non-public object fields

Heuristics built-in to deal with common types

User can help if neededvoid (Foo foo) { if (foo.Value == 123) throw …[PexFactoryMethod]Foo Create(Bar bar) { return new Foo(bar);}

Page 67: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Exercise Limitations

Goal: Understand limitations of DSE. PexGoal/PexExpectedGoals Apply Pex to

if (File.Exists(fileName)) PexGoal.Reached();

if (DateTime.Parse(s).Year == 2009) PexGoal.Reached();

class Foo { private Foo() {} }…if (foo != null) PexGoal.Reached();

Page 68: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Patternshow to create objectsTips and tricks

Page 69: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Creating complex objectsProblem:• Constraint solver determines

test inputs = initial state of test• Most classes hide their state (private fields)• State is initialized by constructor, and can be

mutated only by calling methods• What sequence of method calls reaches a

given target state?• There may be no such sequence• In general, undecidable

Two approaches:• (Guided) exploration of constructor/mutator

methods• Testing with class invariants

Page 70: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Example: ArrayList

Specification:

[PexMethod]public void ArrayListTest(ArrayList al, object o){ PexAssume.IsTrue(al != null); int len = al.Count; al.Add(o); PexAssert.IsTrue(al[len] == o);}

Page 71: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Factory methods Parameterized factories create and configure

objects Explicit: Public static method annotated with

[PexFactoryMethod] Implicit: Pex guesses “best” constructor/setters

Result: Exploration of reachable states Reachable using factory method Reachable within configured bounds Under-approximation of possible states

Object creation:Guided Exploration

Page 72: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

We will now describe how you can create objects via the exploration of a class invariant.

Write class invariant as boolean-valued parameterless method Refers to private fields Must be placed in implementation code

Write special constructor for testing only May be marked as "debug only" Constructor sets fields, assumes invariant

Result: Exploration of feasible states May include states that are not reachable

Object creation:Class invariants

Page 73: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Open project “ArrayListSample”. Explore AddTestExplicit Explore AddTestImplicit

Inspect generated test cases Notice constructor implicitly used by Pex

Exercise:Factory methods

Page 74: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Exercise:Factory method by invariant Edit code of ArrayList class: Add “ad-hoc” Invariant method:

Add DEBUG-only constructor that allows to configure object freely, and then checks invariant:

private bool Invariant() { return this._items != null && this._size >= 0 && this._items.Length >= this._size; }

#if DEBUG public ArrayList(object[] items, int size) { this._items = items; this._size = size; if (!this.Invariant()) throw new Exception(); }#endif

Page 75: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Patternsfor Parameterized Unit TestsTips and tricks

Page 76: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Pattern4A

Assume, Arrange, Act, Assert

[PexMethod]void Add(List target, T value) { PexAssume.IsNotNull(target); // assume var count = target.Count; // arrange target.Add(value); // act Assert(target.Count == count + 1)//assert}

Page 77: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

PatternRoundtrip

For an API f(x), f-1(f(x)) = x for all x

void PropertyRoundtrip(string value) { var target = new Foo(); target.Name = value; var roundtripped = target.Name; Assert.AreEqual(value, roundtripped);}

Page 78: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

PatternRoundtrip

For an API f(x), f-1(f(x)) = x for all x

void ToStringParseRoundtrip(int value) { string s = value.ToString(); int parsed = int.Parse(s); Assert.AreEqual(value, parsed);}

Page 79: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

PatternSanitized Roundtrip

For an API f(x), f-1(f(f-1(x)) = f-1(x) for all x

void ParseToString(string x) { var normalized = int.Parse(x); var intermediate = normalized.ToString(); var roundtripped = int.Parse(intermediate); Assert(normalized == roundtripped);}

Page 80: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

PatternState Relation

Observe a state change

void ContainedAfterAdd(string value) { var list = new List<string>(); list.Add(value); Assert.IsTrue(list.Contains(value));}

Page 81: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

PatternSame Observable Behavior

Given two methods f(x) and g(x), and a method b(y) that observes the result or the exception behavior of a method, assert that f(x) and g(x) have same observable behavior under b, i.e. b(f(x)) = b(g(x)) for all x.

public void ConcatsBehaveTheSame( string left, string right) { PexAssert.AreBehaviorsEqual( () => StringFormatter.ConcatV1(left, right), () => StringFormatter.ConcatV2(left, right));}

Page 82: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

PatternCommutative Diagram Given two implementations f and g of the

same function, each possible requiring a different number of steps, i.e. f(x)=f1(f2(…(fn(x)…)), and g(x)=g1(g2(… (gm(x)…)), then it should hold thatf1(f2(…(fn(x))…) = g1(g2(…(gm(x)…)) for all x.

string Multiply(string x, string y);int Multiply(int x, int y);

void CommutativeDiagram1(int x, int y) { string z1 = Multiply(x, y).ToString(); string z2 = Multiply(x.ToString(), y.ToString()); PexAssert.AreEqual(z1, z2);}

Page 83: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

PatternAllowed Exception

Allowed exception -> negative test case

[PexAllowedException(typeof(ArgumentException))]void Test(object item) { var foo = new Foo(item) // validates item// generated test (C#)[ExpectedException(typeof(ArgumentException))]void Test01() { Test(null); // argument check}

Page 84: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

PatternReachability

Indicate which portions of a PUT should be reachable.

[PexExpectedGoals]public void InvariantAfterParsing(string input){ ComplexDataStructure x; bool success = ComplexDataStructure.TryParse( input, out x); PexAssume.IsTrue(success); PexGoal.Reached(); x.AssertInvariant();}

Page 85: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

PatternRegression Tests

Generated test asserts any observed value Return value, out parameters, PexGoal

When code evolves, breaking changes in observable will be discovered

int AddTest(int a, int b) { return a + b; }

void AddTest01() { var result = AddTest(0, 0); Assert.AreEqual(0, result);}

Page 86: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Exercise Patterns

Goal: Identify and apply patterns Apply patterns to parameterized unit tests

of TrimEnd.

Page 87: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

ParameterizedModels

Page 88: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Unit test: while it is debatable what a ‘unit’ is, a ‘unit’ should be small.

Integration test: exercises large portions of a system.

Observation: Integration tests are often “sold” as unit tests

White-box test generation does not scale well to integration test scenarios.

Possible solution: Introduce abstraction layers, and mock components not under test

Unit Testing vs. Integration Testing

Page 89: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

AppendFormat(null, “{0} {1}!”, “Hello”, “World”); “Hello World!”

.Net Implementation:

public StringBuilder AppendFormat( IFormatProvider provider, char[] chars, params object[] args) {

if (chars == null || args == null) throw new ArgumentNullException(…); int pos = 0; int len = chars.Length; char ch = '\x0'; ICustomFormatter cf = null; if (provider != null) cf =

(ICustomFormatter)provider.GetFormat(typeof(ICustomFormatter)); …

ExampleTesting with Interfaces

Page 90: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Introduce a mock class which implements the interface.

Write assertions over expected inputs, provide concrete outputs

public class MFormatProvider : IFormatProvider {

public object GetFormat(Type formatType) { Assert.IsTrue(formatType != null); return new MCustomFormatter(); }}

Problems: Costly to write detailed behavior by example How many and which mock objects do we need to

write?

Stubs / Mock Objects

Page 91: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Parameterized Mock Objects - 1 Introduce a mock class which implements the

interface. Let an oracle provide the behavior of the mock

methods.

public class MFormatProvider : IFormatProvider {

public object GetFormat(Type formatType) { … object o = call.ChooseResult<object>(); return o; }}

Result: Relevant result values can be generated by white-box test input generation tool, just as other test inputs can be generated! 92

Page 92: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Exercise: “AppendFormatSample”AppendFormat

Show AppendFormat code Show AppendFormat test Run Pex

93

Page 93: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Chosen values can be shaped by assumptions

public class MFormatProvider : IFormatProvider {

public object GetFormat(Type formatType) { … object o = call.ChooseResult<object>(); PexAssume.IsTrue(o is ICustomFormatter);

return o; }}

(Note: Assertions and assumptions are “reversed” when compared to parameterized unit tests.)

Parameterized Mock Objects - 2

94

Page 94: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Models from Choices

Choices to build parameterized models

class PFileSystem : IFileSystem { // cached choices PexChosenIndexedValue<string,string> files; string ReadFile(string name) { var content = this.files[name]; if (content == null) throw new FileNotFoundException(); return content; }}

Page 95: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Exercise Parameterized Models

Goal: Test a ‘CopyFile’ method with a File System model

Write a CopyFile method using IFileSystem

Implement IFileSystem with System.IO.File and use it to test Copy.

Write a parameterized model for IFileSystem and use it to test Copy.

interface IFileSystem { string ReadFile(string fileName); void WriteFile(string name, string content);}

Page 96: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Code Contracts SupportDesign By Contracts meets Automated Whitebox Testing

Page 97: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Code Contracts

http://research.microsoft.com/en-us/projects/contracts/

Library to state preconditions, postconditions, invariants

Supported by two tools: Static Checker Rewriter: turns Code Contracts into runtime

checks Pex analyses the runtime checks

Contracts act as Test Oracle Pex may find counter examples for

contracts Missing Contracts may be suggested

Page 98: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

If present, Pex leverages [ContractInvariantMethod] to create objects via reflection and checking if invariant holds: Install Code Contracts:

Add reference to Microsoft.Contracts library Add empty [ContractInvariantMethod] Run Pex, click on “Add Invariant” Repeat, edit manually

Exercise: (optional)Class invariants with Code Contracts

[ContractInvariantMethod]protected void Invariant() { Contract.Invariant(this._items != (object[])null); Contract.Invariant( (uint)(this._size) <= (uint)(this._items.Length));}

Page 99: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Code Contracts allow specification of interface contracts

Pex‘ stubs framework can leverage contracts to check input and restrict output of mock objects.

Consider the following interfaces annotated with contracts (using Spec# notation):

interface IFormatProvider { object GetFormat(Type formatType) requires formatType != null; ensures result != null && formatType.IsAssignableFrom(result.GetType());

}

Design-by-contractvs. Parameterized Models

Page 100: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Exercise: Testing with Interface Contracts

Create IFormatProvider interface with Code Contractsin code-under-test project

Create (parameterized) test project Show stubs Create parameterized unit test using

IFormatProvider Explore parameterized unit test

Page 101: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Wrapping up

Page 102: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Some Related Toolsfor Data-Generation Random input generators: many Combining random testing and constraint

solving DART, CUTE, EXE, KLEE, CREST (C) jCUTE, jFuzz (Java) SAGE (X86) …

Program model checkers JPF, Kiasan/KUnit (Java), XRT (.NET)

Commercial tools AgitarOne, …

103

Page 103: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Pex on MSDN DevLabsIncubation Project for Visual Studio 2010

Page 104: Tutorial Nikolai Tillmann, Peli de Halleux, Wolfram Schulte (Microsoft Research) Tao Xie (North Carolina State University)

Thank you

http://research.microsoft.com/pexhttp://codeplex.com/Pexhttps://sites.google.com/site/asergrp/