2

Chapter 8 in FP in Scala talks about property based testing and covers how to build a library from scratch. A high level summary of the API is included below:

    //generator of random test cases
    case class Gen[+A](sample: State[RNG,A])

    //generator of random test cases with specified size
    case class SGen[+A](g: Int => Gen[A])
    
    //property that runs assertion
    case class Prop(run: (MaxSize,TestCases,RNG) => Result)
    
    //combines random generator with predicates and returns a property
    def forAll[A](g: Int => Gen[A])(f: A => Boolean): Prop

The following implementation of forAll first creates a sequence of properties, each with an size of 0,1,...max (or n, whichever is lower). It then creates a single property by combining them with && while setting the number of test cases per property to casesPerSize

def forAll[A](g: Int => Gen[A])(f: A => Boolean): Prop = Prop {
    (max,n,rng) =>
      val casesPerSize = (n - 1) / max + 1
      val props: Stream[Prop] =
        Stream.from(0).take((n min max) + 1).map(i => forAll(g(i))(f))
      val prop: Prop =
        props.map(p => Prop { (max, n, rng) =>
          p.run(max, casesPerSize, rng)
        }).toList.reduce(_ && _)
      prop.run(max,n,rng)
  }

What I do not understand is why casesPerSize is calculated as

val casesPerSize = (n - 1) / max + 1

Taking a specific example, if I assume n=95, max=10 then there will be 11 properties with size from 0 to 10, each of which will generate 10 test cases. Since there is just 1 unique test case for size 0, that would still mean 110 - 9 = 101 unique test cases. So how does it ensure that no more than n test cases are generated?

  • There's a recursion there Stream.from(0).take((n min max) + 1).map(i => forAll(g(i))(f)) – Arnon Rotem-Gal-Oz Mar 20 '22 at 10:31
  • The output is going to be a stream of properties, which is lazily evaluated. Nothing happens till the actual evaluation of returned prop by forcing run through passing parameters. – Rupam Bhattacharjee Mar 20 '22 at 10:46
  • right- but then the next line does just that - but maybe I don't understand your question – Arnon Rotem-Gal-Oz Mar 20 '22 at 10:56
  • The next line just combines the properties using & operator, a primitive for property composition. My question relates to casesPerSize calculation. Specifically, how does it ensure that no more than n tests are generated. I have an example included in my question – Rupam Bhattacharjee Mar 20 '22 at 11:40

0 Answers0