25
DEBUGGING AND TESTING WITH SCALACHECK Martina Seidl 2018/11/12

Debugging and Testing with ScalaCheckfmv.jku.at/dbg/sc.pdf · automatic testing of properties automatic generation of test data precise control of test data generation automatic simplification

  • Upload
    others

  • View
    22

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Debugging and Testing with ScalaCheckfmv.jku.at/dbg/sc.pdf · automatic testing of properties automatic generation of test data precise control of test data generation automatic simplification

DEBUGGING AND TESTINGWITH SCALACHECK

Martina Seidl2018/11/12

Page 2: Debugging and Testing with ScalaCheckfmv.jku.at/dbg/sc.pdf · automatic testing of properties automatic generation of test data precise control of test data generation automatic simplification

Some Words on Scala

� Scala is object-oriented� every value is an object� classes and traits: types and behavior of objects� inheritance

� Scala is functional� every function is a value� anonymous functions� higher-order functions� support of currying� pattern matching

� Scala is statically typed� generic classes, polymorphic methods� variance annotations� upper and lower type bounds

1/24

Page 3: Debugging and Testing with ScalaCheckfmv.jku.at/dbg/sc.pdf · automatic testing of properties automatic generation of test data precise control of test data generation automatic simplification

Scala By Example I (from [4])

� class in Java:

1 p u b l i c c lass Person {2 p u b l i c f i n a l S t r i n g name ;3 p u b l i c f i n a l i n t age ;4 Person ( S t r i n g name, i n t age ) {5 t h i s . name = name ;6 t h i s . age = age ;7 }8 }

� class in Scala:

1 c lass Person ( va l name : St r ing ,2 va l age : I n t ) { }

2/24

Page 4: Debugging and Testing with ScalaCheckfmv.jku.at/dbg/sc.pdf · automatic testing of properties automatic generation of test data precise control of test data generation automatic simplification

Scala By Example I (from [4])

� filtering in Java (before Java 8):

1 Person [ ] people ; Person [ ] minors ; Person [ ] adu l t s ;2 . . .3 Ar rayL i s t <Person> mino rsL i s t =4 new Ar rayL i s t <Person > ( ) ;5 Ar rayL i s t <Person> a d u l t s L i s t =6 new Ar rayL i s t <Person > ( ) ;7 f o r ( i n t i = 0 ; i < people . leng th ; i ++)8 ( people [ i ] . age < 18 ? mino rsL i s t :9 a d u l t s L i s t ) . add ( people [ i ] ) ;10 minors = mino rsL i s t . toAr ray ( people ) ;11 adu l t s = a d u l t s L i s t . toAr ray ( people ) ;

� filtering in Scala:

1 va l people : Array [ Person ]2 va l ( minors , adu l t s ) =3 people p a r t i t i o n ( _ . age < 18) 3/24

Page 5: Debugging and Testing with ScalaCheckfmv.jku.at/dbg/sc.pdf · automatic testing of properties automatic generation of test data precise control of test data generation automatic simplification

Scala By Example II (adapted from [1])

1 def s o r t ( xs : Array [ I n t ] ) {2

3 def swap ( i : I n t , j : I n t ) {4 va l t = xs ( i ) ; xs ( i ) = xs ( j ) ; xs ( j ) = t5 }6

7 def so r t1 ( l : I n t , r : I n t ) {8 . . .9 }

10

11 so r t1 (0 , xs . leng th − 1)12 }

4/24

Page 6: Debugging and Testing with ScalaCheckfmv.jku.at/dbg/sc.pdf · automatic testing of properties automatic generation of test data precise control of test data generation automatic simplification

Scala By Example II (adapted from [1])

1 def so r t1 ( l : I n t , r : I n t ) {2

3 va l p i v o t = xs ( ( l + r ) / 2)4 var i = l ; var j = r5

6 whi le ( i <= j ) {7 whi le ( xs ( i ) < p i v o t ) i += 18 whi le ( xs ( j ) > p i v o t ) j −= 19 i f ( i <= j ) {

10 swap ( i , j )11 i += 112 j −= 113 }14 }15

16 i f ( j < r ) so r t1 ( i , r )17 }

5/24

Page 7: Debugging and Testing with ScalaCheckfmv.jku.at/dbg/sc.pdf · automatic testing of properties automatic generation of test data precise control of test data generation automatic simplification

Scala By Example II (adapted from [1])

1 def s o r t ( xs : Array [ I n t ] ) : Array [ I n t ] = {2 i f ( xs . leng th <= 1) xs3 else {4

5 va l p i v o t = xs ( xs . leng th / 2)6

7 Array . concat (8 s o r t ( xs f i l t e r ( p i v o t <) ) ,9 xs f i l t e r ( p i v o t ==) ,

10 s o r t ( xs f i l t e r ( p i v o t >) ) )11 }12 }

6/24

Page 8: Debugging and Testing with ScalaCheckfmv.jku.at/dbg/sc.pdf · automatic testing of properties automatic generation of test data precise control of test data generation automatic simplification

The Power of Properties

The specification of properties ...

� ... helps to understand what the program shall do

� ... helps to understand what the program actually does

� ... helps to talk about the program

� ... can help to find an algorithm

� ... is valuable for debugging

7/24

Page 9: Debugging and Testing with ScalaCheckfmv.jku.at/dbg/sc.pdf · automatic testing of properties automatic generation of test data precise control of test data generation automatic simplification

What does ScalaCheck do?

� User:

� specification of properties which should always hold

� definition of random data for testing properties

� no worries about missed test cases

� ScalaCheck:

� automatic generation of test cases

� checking if properties hold

� shrinking (minimization of failing test cases)

8/24

Page 10: Debugging and Testing with ScalaCheckfmv.jku.at/dbg/sc.pdf · automatic testing of properties automatic generation of test data precise control of test data generation automatic simplification

ScalaCheck is ...

� ... an automated, property based testing tool for Scala/Java

� ... an extended port of Haskell QuickCheck

� ... available at www.scalacheck.org

first example:

1 ob jec t MyPropert ies extends2 Proper t i es ( " MyPropert ies " ) {3

4 proper ty ( "same leng th " ) =5 f o r A l l { ( a : [ I n t ] ) =>6 a . leng th == s o r t ( a ) . leng th7 }8 }

9/24

Page 11: Debugging and Testing with ScalaCheckfmv.jku.at/dbg/sc.pdf · automatic testing of properties automatic generation of test data precise control of test data generation automatic simplification

ScalaChecks Highlights

� automatic testing of properties� automatic generation of test data� precise control of test data generation� automatic simplification of failing test cases� support for stateful testing of command sequences� simplification of failing command sequences� direct testing of property object from the command

scala> import org.scalacheck.Prop.forAll

import org.scalacheck.Prop.forAll

scala> val overflow = forAll { (n: Int) => n > n-1 }

overflow: org.scalacheck.Prop = Prop

scala> overflow.check

! Falsified after 6 passed tests.

> ARG_0: -2147483648

10/24

Page 12: Debugging and Testing with ScalaCheckfmv.jku.at/dbg/sc.pdf · automatic testing of properties automatic generation of test data precise control of test data generation automatic simplification

Basic Concepts

� propertiesorg.scalacheck.Prop

� generatorsorg.scalacheck.Gen

� test runnerorg.scalacheck.Test

11/24

Page 13: Debugging and Testing with ScalaCheckfmv.jku.at/dbg/sc.pdf · automatic testing of properties automatic generation of test data precise control of test data generation automatic simplification

Property

� testable unit in ScalaCheck� class: org.scalacheck.Prop� generation:

� specification of new property� combination of other properties� use specialized methods

scala> object StringProps extends Properties("String") {

|

| property("startsWith") = forAll ( (a:String, b:String) =>

(a+b).startsWith(a))

| }

defined module StringProps

scala> StringProps.check

+ String.startsWith: OK, passed 100 tests.

12/24

Page 14: Debugging and Testing with ScalaCheckfmv.jku.at/dbg/sc.pdf · automatic testing of properties automatic generation of test data precise control of test data generation automatic simplification

Universally Quantified Property (ForallProperty)

� create property: org.scalacheck.Prop.forAll� in: function which returns Boolean or a property� out: property

� check property: call of check method

1 impor t org . scalacheck . Prop . f o r A l l2

3 va l propReverseList = f o r A l l {4 l : L i s t [ S t r i n g ] =>5 l . reverse . reverse == l }6

7 va l propConcatStr ing = f o r A l l {8 ( s1 : S t r ing , s2 : S t r i n g ) =>9 ( s1 + s2 ) . endsWith ( s2 ) }

13/24

Page 15: Debugging and Testing with ScalaCheckfmv.jku.at/dbg/sc.pdf · automatic testing of properties automatic generation of test data precise control of test data generation automatic simplification

Data Generator

� generation of test data for� custom data types� subsets of standard data types

� representation: org.scalacheck.Gen

1 va l myGen = f o r {2 n <− Gen . choose (10 ,20)3 m <− Gen . choose (2* n , 500)4 } y i e l d ( n ,m)5

6 va l vowel = Gen . oneOf ( ’A ’ , ’E ’ , ’ I ’ , ’O ’ , ’U ’ )7

8 va l vowel1 = Gen . frequency ( (3 , ’A ’ ) , (4 , ’E ’ ) ,9 (2 , ’ I ’ ) , (3 , ’O ’ ) , (1 , ’U ’ ) )

14/24

Page 16: Debugging and Testing with ScalaCheckfmv.jku.at/dbg/sc.pdf · automatic testing of properties automatic generation of test data precise control of test data generation automatic simplification

A Generator for Trees

1 sealed abs t rac t c lass Tree2 case c lass Node ( l e f t : Tree , r i g h t : Tree , v : I n t )

extends Tree3 case ob jec t Leaf extends Tree4

5 va l genLeaf = const ( Leaf )6

7 va l genNode = f o r {8 v <− a r b i t r a r y [ I n t ]9 l e f t <− genTree

10 r i g h t <− genTree11 } y i e l d Node ( l e f t , r i g h t , v )12

13 def genTree : Gen [ Tree ] = oneOf ( genLeaf , genNode )

15/24

Page 17: Debugging and Testing with ScalaCheckfmv.jku.at/dbg/sc.pdf · automatic testing of properties automatic generation of test data precise control of test data generation automatic simplification

Statistics on Test Data

� collect infos on created test data� inspection of distribution� only trivial test cases?

1 def ordered ( l : L i s t [ I n t ] ) = l == l . s o r t ( _ > _ )2

3 va l myProp = f o r A l l { l : L i s t [ I n t ] =>4 c l a s s i f y ( ordered ( l ) , " ordered " ) {5 c l a s s i f y ( l . l eng th > 5 , " l a rge " , " smal l " ) {6 l . reverse . reverse == l7 . . .

scala> myProp.check

+ OK, passed 100 tests.

> Collected test data:

78% large 16% small, ordered 6% small

16/24

Page 18: Debugging and Testing with ScalaCheckfmv.jku.at/dbg/sc.pdf · automatic testing of properties automatic generation of test data precise control of test data generation automatic simplification

Conditional Properties

� sometimes specifications are implications

� implication operator

� restricts number of test cases

� problem: condition is hard or impossible to fulfill

� property does not only pass or fail, but could be undecidedif implication condition does not get fulfilled.

1 proper ty ( " f i r s t E l e m e n t " ) =2 Prop . f o r A l l {3 ( xs : L i s t [ I n t ] ) => ( xs . s i ze > 0) ==>4 ( xs . head == xs ( 0 ) )5 }

17/24

Page 19: Debugging and Testing with ScalaCheckfmv.jku.at/dbg/sc.pdf · automatic testing of properties automatic generation of test data precise control of test data generation automatic simplification

Combining Properties

combine existing properties to new ones

val p1 = forAll(...)

val p2 = forAll(...)

val p3 = p1 && p2

val p4 = p1 || p2

val p5 = p1 == p2

val p6 = all(p1, p2) // same as p1 && p2

val p7 = atLeastOne(p1, p2) // same as p1 || p2

18/24

Page 20: Debugging and Testing with ScalaCheckfmv.jku.at/dbg/sc.pdf · automatic testing of properties automatic generation of test data precise control of test data generation automatic simplification

Test Case Execution

� Module Test

� execution of the tests� generation of the arguments� evaluation of the properties� increase of size of test parameters� reports success (passed) after certain number of tries

� Testing parameters in Test.Parameters

� number of times a property should be tested� size bounds of test data� number of tries in case of failure� callback

� Statistics in Test.Result

� test properties with Test.check

19/24

Page 21: Debugging and Testing with ScalaCheckfmv.jku.at/dbg/sc.pdf · automatic testing of properties automatic generation of test data precise control of test data generation automatic simplification

Test Case Minimisation

� ScalaCheck tries to shrink failing test cases before they arereported

� Default by Prop.forAll

� No shrinking: Prop.forAllNoShrink

1 va l p1 = fo rA l lNoShr ink ( a r b i t r a r y [ L i s t [ I n t ] ] ) (2 l => l == l . removeDupl icates )

counter example:

List(8, 0, -1, -3, -8, 8, 2, -10, 9, 1, -8)

1 va l p3 = f o r A l l ( ( l : L i s t [ I n t ] ) =>2 l == l . removeDupl icates )

counter example: List(-5, -5)

20/24

Page 22: Debugging and Testing with ScalaCheckfmv.jku.at/dbg/sc.pdf · automatic testing of properties automatic generation of test data precise control of test data generation automatic simplification

Customized Shrinking

� Definition of custom shrinking methods is possible

� Implicit method which returns Shrink[T ] instance

� Important: instances get smaller (otherwise loops possible)

1 i m p l i c i t def shr inkTuple2 [ T1 , T2 ]2 ( i m p l i c i t s1 : Shr ink [ T1 ] , s2 : Shr ink [ T2 ]3 ) : Shr ink [ ( T1 , T2 ) ] = Shr ink { case ( t1 , t2 ) =>4 ( f o r ( x1 <− sh r i nk ( t1 ) ) y i e l d ( x1 , t2 ) ) append5 ( f o r ( x2 <− sh r i nk ( t2 ) ) y i e l d ( t1 , x2 ) )6 }

21/24

Page 23: Debugging and Testing with ScalaCheckfmv.jku.at/dbg/sc.pdf · automatic testing of properties automatic generation of test data precise control of test data generation automatic simplification

State-Full Testing

� What about testing combinations of functions?

� Solution: org.scalacheck.Commands

� Example: Test the behavior of a counter

1 c lass Counter {2 p r i v a t e var n = 03 def inc = n += 14 def dec = n −= 15 def get = n6 def rese t = n = 07 }

22/24

Page 24: Debugging and Testing with ScalaCheckfmv.jku.at/dbg/sc.pdf · automatic testing of properties automatic generation of test data precise control of test data generation automatic simplification

State-full Testing

1

2 ob jec t Coun te rSpec i f i ca t i on extends Commands {3 type State = I n t4 type Sut = Counter5

6 def newSut ( s t a t e : State ) : Sut = new Counter7

8

9 case ob jec t Inc extends UnitCommand {10 def run ( sut : Sut ) : Un i t = sut . i nc11 def nextSta te ( s t a t e : State ) : State = s ta te + 112 def preCond i t ion ( s t a t e : State ) : Boolean = t rue13 def pos tCond i t ion ( s t a t e : State , success : Boolean ) :

Prop = success14 }15

16

17 } 23/24

Page 25: Debugging and Testing with ScalaCheckfmv.jku.at/dbg/sc.pdf · automatic testing of properties automatic generation of test data precise control of test data generation automatic simplification

References

[1] M. Odersky. Scala By Example, EPFL, 2014

[2] ScalaCheck Project Site: www.scalacheck.org

[3] Scala Project Site. ScalaCheck,http://www.scalacheck.org/

[4] M. Odersky. Scala: How to make best use of functionsand objects, Tutorial slides, ACM SAC 2010

[5] R. Nilsson. ScalaCheck UserGuide,https://github.com/rickynils/scalacheck/blob/master/doc/UserGuide.md

24/24