scalaintermediate
Property-Based Testing with ScalaCheck
Write property-based tests with ScalaCheck: generators, properties, shrinking, and custom Arbitrary.
scalaPress ⌘/Ctrl + Shift + C to copy
import org.scalacheck.*
import org.scalacheck.Prop.*
import org.scalacheck.Gen
// Basic properties
object StringProps extends Properties("String"):
property("startsWith") = forAll { (a: String, b: String) =>
(a + b).startsWith(a)
}
property("endsWith") = forAll { (a: String, b: String) =>
(a + b).endsWith(b)
}
property("concat length") = forAll { (a: String, b: String) =>
(a + b).length == a.length + b.length
}
property("substring") = forAll { (a: String, b: String, c: String) =>
(a + b + c).contains(b)
}
// List properties
object ListProps extends Properties("List"):
property("reverse reverse") = forAll { (l: List[Int]) =>
l.reverse.reverse == l
}
property("sort is sorted") = forAll { (l: List[Int]) =>
val sorted = l.sorted
sorted.zip(sorted.tail).forall((a, b) => a <= b) || sorted.length <= 1
}
property("filter subset") = forAll { (l: List[Int]) =>
l.filter(_ > 0).forall(_ > 0)
}
property("map preserves length") = forAll { (l: List[Int]) =>
l.map(_ * 2).length == l.length
}
// Custom generators
case class Email(local: String, domain: String):
override def toString = s"$local@$domain"
case class User(name: String, age: Int, email: Email)
object Generators:
val genEmail: Gen[Email] = for
local <- Gen.alphaNumStr.suchThat(_.nonEmpty)
domain <- Gen.oneOf("test.com", "example.org", "mail.io")
yield Email(local, domain)
val genUser: Gen[User] = for
name <- Gen.alphaStr.suchThat(s => s.nonEmpty && s.length <= 50)
age <- Gen.choose(0, 120)
email <- genEmail
yield User(name, age, email)
val genEvenInt: Gen[Int] = Gen.choose(1, 1000).map(_ * 2)
val genPosInt: Gen[Int] = Gen.posNum[Int]
val genColor: Gen[String] = Gen.oneOf("red", "green", "blue", "yellow")
given Arbitrary[Email] = Arbitrary(genEmail)
given Arbitrary[User] = Arbitrary(genUser)
object UserProps extends Properties("User"):
import Generators.given
property("age in range") = forAll { (user: User) =>
user.age >= 0 && user.age <= 120
}
property("email has @") = forAll { (user: User) =>
user.email.toString.contains("@")
}
property("name non-empty") = forAll { (user: User) =>
user.name.nonEmpty
}
object MathProps extends Properties("Math"):
import Generators.*
property("even * even = even") = forAll(genEvenInt, genEvenInt) {
(a: Int, b: Int) =>
(a.toLong * b.toLong) % 2 == 0
}
property("abs non-negative") = forAll { (n: Int) =>
n == Int.MinValue || Math.abs(n) >= 0
}Use Cases
- Exhaustive testing with random inputs
- Finding edge cases automatically
- Specification-driven testing
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
scalaintermediate
Unit Testing with ScalaTest
Write unit tests with ScalaTest: FunSuite, FlatSpec, matchers, mocking, and async testing.
Best for: Unit testing Scala code
#scala#testing
scalaintermediate
Testing with Mocks and Stubs
Write testable Scala code with trait-based mocks, stubs, and dependency substitution.
Best for: Unit testing with dependency injection
#scala#testing
scalaintermediate
Testing with Specs2 Framework
Write readable tests with specs2: acceptance specs, matchers, data tables, and mock integration.
Best for: Behavior-driven development
#scala#testing
scalabeginner
Scala Hello World Application
Create a basic Scala application with main method, string interpolation, and val/var basics.
Best for: Getting started with Scala
#scala#basics