CtrlK
BlogDocsLog inGet started
Tessl Logo

testland/quickcheck-testing

Authors property-based tests for Haskell using QuickCheck (the original PBT library) and for Scala via ScalaCheck (the JVM port) - wires `quickCheck` (Haskell) / `forAll` (ScalaCheck) drivers, defines `Arbitrary` instances or generators, uses `shrink` to find minimal counterexamples, and integrates with HSpec / Tasty (Haskell) or specs2 / ScalaTest. Use when the codebase is Haskell or Scala and the team wants the canonical PBT library that the entire family (Hypothesis / fast-check / proptest / jqwik) was inspired by.

74

Quality

93%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

Overview
Quality
Evals
Security
Files

quickcheck-reference.mdreferences/

QuickCheck / ScalaCheck reference

Detailed lookup material for quickcheck-testing. Sources: QuickCheck on Hackage, ScalaCheck (scalacheck.org).

Pinned versions

  • QuickCheck (Haskell): 2.18.0.0 latest stable at source-fetch (build-depends: QuickCheck >= 2.18).
  • ScalaCheck (Scala): 1.18.0; ScalaTest-plus integration via scalatest-propspec 3.2.18.

Check the sources before bumping.

QuickCheck modules

ModuleUse
Test.QuickCheckMain entry: quickCheck, verboseCheck.
Test.QuickCheck.ArbitraryArbitrary typeclass for custom types.
Test.QuickCheck.GenCustom generators.
Test.QuickCheck.FunctionFunction generation.
Test.QuickCheck.Monadic"for testing stateful/monadic code" (qch).

Combinators (Haskell)

-- Quantify per-test scope
prop_sortIdempotent :: Property
prop_sortIdempotent = forAll (listOf1 arbitrary :: Gen [Int]) $ \xs ->
  sort (sort xs) == sort xs

-- Classify cases for distribution monitoring
prop_lengthClassified :: [Int] -> Property
prop_lengthClassified xs = classify (null xs) "empty" $
                            classify (length xs > 100) "large" $
                            length (reverse xs) == length xs

forAll quantifies inline; classify / label track distribution.

ScalaTest integration

import org.scalatest.propspec.AnyPropSpec
import org.scalatest.matchers.should.Matchers
import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks

class UserPropSpec extends AnyPropSpec with Matchers with ScalaCheckPropertyChecks {

  property("reverse is involutive") {
    forAll { (xs: List[Int]) =>
      xs.reverse.reverse shouldBe xs
    }
  }
}

Anti-patterns

Anti-patternWhy it failsFix
Skipping shrink in custom ArbitraryFailures aren't shrunk; counterexample messages are huge.Always implement shrink (Step 4).
Heavy ==> (Haskell) / suchThat (Scala) preconditionsCases discarded; "Gave up after N tests" warning.Restructure the generator to produce only valid inputs (Step 4-5).
arbitrary without Arbitrary typeclass instance for custom typesCompile error / runtime "no instance" - must define instance per type.Define Arbitrary T instance (Step 4).
Random seed in CIFailures hard to reproduce.Fixed seed (Step 8).
quickCheck from MainMixes test code with executable.Use HSpec / Tasty (Haskell) or ScalaTest (Scala) for organization.
Properties that always pass triviallyNo actual verification; false confidence.verboseCheck to see distribution; reformulate.

Limitations

  • Haskell-specific syntax (Haskell QuickCheck only). Teams unfamiliar with Haskell will find the syntax off-putting; ScalaCheck is more accessible.
  • Older API quirks. QuickCheck pre-dates many modern PBT conveniences; jqwik / Hypothesis ergonomics are smoother for newcomers.
  • No race-condition detection. Unlike fast-check's fc.scheduler, basic QuickCheck doesn't model concurrent interleavings.
  • Shrinking can be slow. Custom shrink implementations need care to terminate.
  • ScalaCheck integration with ScalaTest can be confusing when multiple property-checking integrations exist (ScalaTest's own generators vs ScalaCheck's).

SKILL.md

tile.json