A comprehensive property-based testing library for Scala and Java applications that enables developers to specify program properties as testable assertions and automatically generates test cases to verify these properties.
—
The ScalaCheck test execution framework provides configurable property testing with parallel processing, custom reporting, seed control, and comprehensive result analysis. It supports both individual property testing and batch execution of property collections.
Comprehensive configuration for test execution behavior and resource management.
sealed abstract class Test.Parameters {
val minSuccessfulTests: Int
val minSize: Int
val maxSize: Int
val workers: Int
val testCallback: Test.TestCallback
val maxDiscardRatio: Float
val customClassLoader: Option[ClassLoader]
val propFilter: Option[String]
val initialSeed: Option[Seed]
val useLegacyShrinking: Boolean
val maxRNGSpins: Int
def withMinSuccessfulTests(minSuccessfulTests: Int): Test.Parameters
def withMinSize(minSize: Int): Test.Parameters
def withMaxSize(maxSize: Int): Test.Parameters
def withWorkers(workers: Int): Test.Parameters
def withTestCallback(testCallback: Test.TestCallback): Test.Parameters
def withMaxDiscardRatio(maxDiscardRatio: Float): Test.Parameters
def withCustomClassLoader(customClassLoader: Option[ClassLoader]): Test.Parameters
def withPropFilter(propFilter: Option[String]): Test.Parameters
def withInitialSeed(seed: Seed): Test.Parameters
def withLegacyShrinking(b: Boolean): Test.Parameters
def withMaxRNGSpins(n: Int): Test.Parameters
}
object Test.Parameters {
val default: Test.Parameters
val defaultVerbose: Test.Parameters
}Usage Examples:
val customParams = Test.Parameters.default
.withMinSuccessfulTests(1000)
.withWorkers(4)
.withMaxSize(50)
.withMaxDiscardRatio(10.0f)
val debugParams = Test.Parameters.default
.withInitialSeed(Seed.fromBase64("abc123...").get)
.withTestCallback(ConsoleReporter(2))Core methods for running individual properties and property collections.
object Test {
def check(params: Test.Parameters, p: Prop): Test.Result
def check(p: Prop)(f: Test.Parameters => Test.Parameters): Test.Result
def check_(params: Test.Parameters, p: Prop): Unit
def check_(p: Prop)(f: Test.Parameters => Test.Parameters): Unit
def checkProperties(prms: Test.Parameters, ps: Properties): Seq[(String, Test.Result)]
def checkProperties_(prms: Test.Parameters, ps: Properties): Unit
}Usage Examples:
val prop = forAll { (x: Int) => x + 0 == x }
// Basic checking
val result = Test.check(Test.Parameters.default, prop)
// Functional parameter modification
val result2 = Test.check(prop)(_.withMinSuccessfulTests(500))
// Silent checking (no return value)
Test.check_(prop)(_.withWorkers(2))
// Batch property checking
object MyProps extends Properties("Math") {
property("addition") = forAll((a: Int, b: Int) => a + b == b + a)
property("multiplication") = forAll((a: Int, b: Int) => a * b == b * a)
}
val allResults = Test.checkProperties(Test.Parameters.default, MyProps)Comprehensive result information including status, statistics, and collected data.
case class Test.Result(
status: Test.Status,
succeeded: Int,
discarded: Int,
freqMap: FreqMap[Set[Any]],
time: Long
) {
def passed: Boolean
}
sealed trait Test.Status
case object Test.Passed extends Test.Status
case class Test.Proved(args: List[Prop.Arg[Any]]) extends Test.Status
case class Test.Failed(args: List[Prop.Arg[Any]], labels: Set[String]) extends Test.Status
case object Test.Exhausted extends Test.Status
case class Test.PropException(args: List[Prop.Arg[Any]], e: Throwable, labels: Set[String]) extends Test.StatusUsage Examples:
val result = Test.check(prop)(_.withMinSuccessfulTests(100))
result.status match {
case Test.Passed => println(s"✓ Property passed with ${result.succeeded} successful tests")
case Test.Failed(args, labels) =>
println(s"✗ Property failed with args: ${args.map(_.arg)}")
println(s"Labels: ${labels.mkString(", ")}")
case Test.Exhausted =>
println(s"⚠ Property exhausted after ${result.discarded} discarded tests")
case Test.PropException(args, e, labels) =>
println(s"💥 Property threw exception: ${e.getMessage}")
case Test.Proved(args) =>
println(s"✓ Property proved with args: ${args.map(_.arg)}")
}
println(s"Execution time: ${result.time}ms")
println(s"Success rate: ${result.succeeded}/${result.succeeded + result.discarded}")Customizable reporting and monitoring during test execution.
trait Test.TestCallback {
def onPropEval(name: String, threadIdx: Int, succeeded: Int, discarded: Int): Unit
def onTestResult(name: String, result: Test.Result): Unit
def chain(testCallback: Test.TestCallback): Test.TestCallback
}
class ConsoleReporter(verbosity: Int, columnWidth: Int = 75) extends Test.TestCallback
object ConsoleReporter {
def apply(verbosity: Int = 0): ConsoleReporter
}Usage Examples:
// Custom callback implementation
class ProgressCallback extends Test.TestCallback {
def onPropEval(name: String, threadIdx: Int, succeeded: Int, discarded: Int): Unit = {
if (succeeded % 10 == 0) print(".")
}
def onTestResult(name: String, result: Test.Result): Unit = {
println(s"\n$name: ${if (result.passed) "PASS" else "FAIL"}")
}
}
// Using console reporter with different verbosity levels
val quietReporter = ConsoleReporter(0) // Minimal output
val verboseReporter = ConsoleReporter(2) // Detailed output
val customReporter = ConsoleReporter(1).chain(new ProgressCallback)
Test.check(prop)(_.withTestCallback(customReporter))Selective execution of properties based on name patterns.
def matchPropFilter(propertyName: String, regex: Regex): BooleanUsage Examples:
val params = Test.Parameters.default.withPropFilter(Some(".*math.*"))
// Only properties with "math" in their name will be executed
Test.checkProperties_(params, AllProperties)
// In a Properties collection
object MathProperties extends Properties("Math") {
property("math.addition") = forAll((a: Int, b: Int) => a + b == b + a)
property("math.multiplication") = forAll((a: Int, b: Int) => a * b == b * a)
property("string.concat") = forAll((s1: String, s2: String) => (s1 + s2).length >= s1.length)
}
// With filter "math.*", only the first two properties will runMulti-threaded test execution for improved performance.
// Configure worker threads
val parallelParams = Test.Parameters.default.withWorkers(8)
// Thread-safe property testing
val heavyProp = forAll(complexDataGen) { data =>
// CPU-intensive property test
expensiveComputation(data)
}
Test.check(heavyProp)(_.withWorkers(4).withMinSuccessfulTests(10000))Deterministic test execution using explicit seeds for reproducibility.
// Create deterministic seed
val seed = Seed.fromBase64("SGVsbG8gV29ybGQhIFRoaXMgaXMgYSB0ZXN0Lg").get
// Use seed for reproducible testing
val reproducibleParams = Test.Parameters.default.withInitialSeed(seed)
Test.check(prop)(_.withInitialSeed(seed))
// Get failing seed from property
val failingProp = Prop.forAll { (x: Int) => x > 0 }.viewSeed("myProperty")
// This will print the seed if the property failsConfiguration options for optimizing test execution performance.
val performanceParams = Test.Parameters.default
.withMinSuccessfulTests(10000) // More thorough testing
.withWorkers(Runtime.getRuntime.availableProcessors()) // Use all CPU cores
.withMaxSize(100) // Larger test cases
.withMaxDiscardRatio(50.0f) // Allow more discards
.withLegacyShrinking(false) // Use modern shrinking
.withMaxRNGSpins(1000000) // More RNG attempts
// For quick smoke tests
val quickParams = Test.Parameters.default
.withMinSuccessfulTests(50)
.withMaxSize(20)
.withWorkers(1)object ApplicationTests extends Properties("Application") {
include(CoreLogicTests)
include(DatabaseTests, "db.")
include(ApiTests, "api.")
override def overrideParameters(p: Test.Parameters): Test.Parameters = {
p.withMinSuccessfulTests(500)
.withWorkers(2)
}
}
// Run all tests
ApplicationTests.check()
// Command line execution
ApplicationTests.main(Array("--verbosity", "2", "--workers", "4"))def analyzeResults(results: Seq[(String, Test.Result)]): Unit = {
val (passed, failed) = results.partition(_._2.passed)
println(s"Summary: ${passed.size} passed, ${failed.size} failed")
failed.foreach { case (name, result) =>
println(s"FAILED: $name")
result.status match {
case Test.Failed(args, labels) =>
println(s" Args: ${args.map(_.arg).mkString(", ")}")
println(s" Labels: ${labels.mkString(", ")}")
case Test.PropException(_, e, _) =>
println(s" Exception: ${e.getMessage}")
case _ =>
}
}
}
val results = Test.checkProperties(Test.Parameters.default, MyProperties)
analyzeResults(results)// Exit with proper codes for CI systems
object CITestRunner {
def main(args: Array[String]): Unit = {
val results = Test.checkProperties(
Test.Parameters.default.withTestCallback(ConsoleReporter(1)),
AllTests
)
val failures = results.count(!_._2.passed)
if (failures > 0) {
println(s"BUILD FAILED: $failures test(s) failed")
System.exit(1)
} else {
println("BUILD PASSED: All tests successful")
System.exit(0)
}
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-scalacheck--scalacheck-2-12