How can I reduce the number of test cases ScalaCheck generates?
Asked Answered
K

1

7

I'm trying to solve two ScalaCheck (+ specs2) problems:

  1. Is there any way to change the number of cases that ScalaCheck generates?

  2. How can I generate strings that contain some Unicode characters?

For example, I'd like to generate about 10 random strings that include both alphanumeric and Unicode characters. This code, however, always generates 100 random strings, and they are strictly alpha character based:

"make a random string" in {
    def stringGenerator = Gen.alphaStr.suchThat(_.length < 40)
    implicit def randomString: Arbitrary[String] = Arbitrary(stringGenerator)

    "the string" ! prop { (s: String) => (s.length > 20 && s.length < 40) ==> { println(s); success; } }.setArbitrary(randomString)
}

Edit

I just realized there's another problem:

  1. Frequently, ScalaCheck gives up without generating 100 test cases

Granted I don't want 100, but apparently my code is trying to generate an overly complex set of rules. The last time it ran, I saw "gave up after 47 tests."

Karilynn answered 21/5, 2015 at 5:40 Comment(0)
O
13

The "gave up after 47 tests" error means that your conditions (which include both the suchThat predicate and the ==> part) are too restrictive. Fortunately it's often not too hard to bake these into your generator, and in your case you can write something like this (which also addresses the issue of picking arbitrary characters, not just alphanumeric ones):

val stringGen: Gen[String] = Gen.chooseNum(21, 40).flatMap { n =>
  Gen.buildableOfN[String, Char](n, arbitrary[Char])
}

Here we pick an arbitrary length in the desired range and then pick that number of arbitrary characters and concatenate them into a string.

You could also increase the maxDiscardRatio parameter:

import org.specs2.scalacheck.Parameters
implicit val params: Parameters = Parameters(maxDiscardRatio = 1024)

But that's typically not a good idea—if you're throwing away most of your generated values your tests will take longer, and refactoring your generator is generally a lot cleaner and faster.

You can also decrease the number of test cases by setting the appropriate parameter:

implicit val params: Parameters = Parameters(minTestsOk = 10)

But again, unless you have a good reason to do this, I'd suggest trusting the defaults.

Obligate answered 21/5, 2015 at 8:36 Comment(3)
Another question comes up... your example (above) includes pretty much all unicode characters (mostly Asian). How can I limit this to generate a more anglo-oriented set of characters, perhaps latin plus some Nordic/Germanic characters...? If you have any ideas I'd very much appreciate it...Karilynn
Right, the arbitrary[Char] in my answer picks from all characters. You could replace it with a custom Gen[Char] built out of the combinators on Gen. Note though that if you're trying to confirm that unusual values don't crash your program, restricting the test cases too much can be counterproductive.Obligate
Note that you can write this a little more straightforwardly with buildableOfN rather than sequence—I've just updated the answer.Obligate

© 2022 - 2024 — McMap. All rights reserved.