quickcheck clojurecheck scalacheck - meetup

22
QuickCheck ClojureCheck ScalaCheck Dave Gurnell Property-based testing with...

Upload: others

Post on 09-Feb-2022

4 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: QuickCheck ClojureCheck ScalaCheck - Meetup

QuickCheckClojureCheckScalaCheck

Dave Gurnell

Property-based testing with...

Page 2: QuickCheck ClojureCheck ScalaCheck - Meetup

Testing(it’s good ...but it’s time consuming)

Page 3: QuickCheck ClojureCheck ScalaCheck - Meetup

cost(maintenance) > cost(development)

Page 4: QuickCheck ClojureCheck ScalaCheck - Meetup

test("reverse an empty list") { assert(List().reverse === List())}

test("reverse a list of length 2") { assert(List("a", "b").reverse === List("b", "a"))}

test("reverse a list with a null in it") { assert(List("a", null).reverse === List(null, "a"))}

test("reverse a palindrome (?!)") { assert("TACOCAT".toList.reverse === "TACOCAT".toList)}

Lots of tests = lots of maintenance...

Page 5: QuickCheck ClojureCheck ScalaCheck - Meetup

How can we get similar coveragewith less code?

Page 6: QuickCheck ClojureCheck ScalaCheck - Meetup

Properties(aka “Invariants”)

Page 7: QuickCheck ClojureCheck ScalaCheck - Meetup

reverse(a ++ b) == reverse(b) ++ reverse(a)

reverse(reverse(a)) == a

endpoint(request).status != 500

i > 0 ==> i/2 < i

Page 8: QuickCheck ClojureCheck ScalaCheck - Meetup

∀a,b reverse(a ++ b) == reverse(b) ++ reverse(a)

∀a reverse(reverse(a)) == a

∀request endpoint(request).status != 500

i > 0 ==> i/2 < i∀i

Problem - these are all universally quantified...

Page 9: QuickCheck ClojureCheck ScalaCheck - Meetup

We can’t test all possible inputs to our properties.

Can we find a representative sample instead?

Page 10: QuickCheck ClojureCheck ScalaCheck - Meetup

Generators(define inputs to properties)

Page 11: QuickCheck ClojureCheck ScalaCheck - Meetup

import org.scalacheck.Gen

val ints = Gen.oneOf(1, 2, 3) // Gen[Int]

ints.sample // => Some(1)ints.sample // => Some(3)ints.sample // => Some(2)

Generators samples values from large datasets

Page 12: QuickCheck ClojureCheck ScalaCheck - Meetup

import org.scalacheck.Gen

val lists = Gen.listOf(Gen.oneOf(1, 2, 3))

lists.sample // => Some(List(1, 3, 2, ... lists.sample // => Some(List())lists.sample // => Some(List(2, 3, 3, ...

Generators samples values from large datasets

Page 13: QuickCheck ClojureCheck ScalaCheck - Meetup

import org.scalacheck.Genimport org.scalacheck.Prop.forAll

val lists = Gen.listOf(Gen.oneOf(1, 2, 3))

val prop = forAll(lists) { list => list.reverse.reverse == list}

Use generators to approximate universal quantification

Page 14: QuickCheck ClojureCheck ScalaCheck - Meetup

import org.scalacheck.Genimport org.scalacheck.Prop.forAll

val lists = Gen.listOf(Gen.oneOf(1, 2, 3))

val prop = forAll(lists) { list => list.reverse.reverse == list}

prop.check // stdout: OK, passed 100 tests.

Use generators to approximate universal quantification

Page 15: QuickCheck ClojureCheck ScalaCheck - Meetup

import org.scalacheck.Genimport org.scalacheck.Prop.forAll

val lists = Gen.listOf(Gen.oneOf(1, 2, 3))

val prop = forAll(lists, lists) { (a, b) => (a ++ b).reverse == b.reverse ++ a.reverse}

prop.check // stdout: OK, passed 100 tests.

Use generators to approximate universal quantification

Page 16: QuickCheck ClojureCheck ScalaCheck - Meetup

import org.scalacheck.Genimport org.scalacheck.Prop.forAll

val lists = Gen.listOf(Gen.oneOf(1, 2, 3))

val prop = forAll(lists, lists) { (a, b) => (a ++ b).reverse == a.reverse ++ b.reverse}

prop.check // stdout: Falsified after 2 tests. // ARG_0: List(0) // ARG_1: List(1)

Use generators to approximate universal quantification

Page 17: QuickCheck ClojureCheck ScalaCheck - Meetup

“Arbitraries”(materialize generators from types)

Page 18: QuickCheck ClojureCheck ScalaCheck - Meetup

import org.scalacheck.Arbitrary.arbitrary

val ints = arbitrary[Int] // Gen[Int]

ints.sample // => Some(2147483647)ints.sample // => Some(-1)

val lists = arbitrary[List[Int]] // Gen[List[Int]]

lists.sample // => Some(List(2120334425, 0, 0, ...lists.sample // => Some(List(-1639755040, 1, ...

Page 19: QuickCheck ClojureCheck ScalaCheck - Meetup

import org.scalacheck.Prop.forAll

forAll { (a: List[Int]) => a.reverse.reverse == a}

forAll { (a: List[Int], b: List[Int]) => (a ++ b).reverse == b.reverse ++ a.reverse}

forAll can grab Arbitraries implicitly

Page 20: QuickCheck ClojureCheck ScalaCheck - Meetup

But wait, there’s more...

Automatic test case reductionDSL for testing side-effects

Generator and property combinators

See the ScalaCheck web site for info!

Page 21: QuickCheck ClojureCheck ScalaCheck - Meetup

References

Page 22: QuickCheck ClojureCheck ScalaCheck - Meetup

Haskell QuickCheckhttp://fsl.cs.illinois.edu/images/3/3d/QuickL.pdf

http://www.haskell.org/haskellwiki/Introduction_to_QuickCheck1

ScalaCheckhttps://github.com/rickynils/scalacheck

Java QuickCheckhttps://bitbucket.org/blob79/quickcheck

ClojureCheckhttps://github.com/jbondeson/clojurecheck