Arrived from Scalacheck?
Welcome to Americium—learn the local language
Table of contents
- Introduction
- Terminology Translation
Trialsas a Monad- Running Tests
- Test Configuration
- Sized Generation
- Custom Shrink Instances
- Auto-Derivation
- Summary
Introduction
If you are coming from Scalacheck, you will find Americium’s approach very familiar but with some key improvements—most notably, integrated shrinkage.
In Americium, you don’t need to write Shrink[T] instances. Shrinkage is automatically derived from the way you build your Trials.
Terminology Translation
Arbitrary and Gen
Gen[T]becomesTrials[T].- There is no direct analogue for
Arbitrary[T]. Instead, you either explicitly pass aTrials[T]or useFactory[T]for auto-derivation (similar toscalacheck-shapeless).
Common Generators
Scalacheck (Gen) |
Americium (api or Trials) |
|---|---|
Gen.choose / chooseNum |
api.integers, api.doubles, api.bigInts, etc. (using range overloads) |
Gen.long / double |
api.longs, api.doubles (no-arg overloads) |
Gen.oneOf(t1, t2, ...) |
api.choose(t1, t2, ...) |
Gen.oneOf(g1, g2, ...) |
api.alternate(g1, g2, ...) |
Gen.frequency |
api.alternateWithWeights |
Gen.const |
api.only |
Gen.delay |
api.delay |
Gen.sequence |
api.sequences |
Gen.listOf |
trials.lists |
Gen.listOfN |
trials.listsOfSize |
Gen.containerOf |
trials.collections or trials.several |
Gen.option |
trials.options |
Gen.either |
trials1.or(trials2) |
Note on naming: Americium’s
TrialsApimethods are typically pluralized (e.g.,api.longsvsGen.long).
Trials as a Monad
Like Gen, Trials is a monad. It provides:
map,flatMap,filtermapFilterwithFilter(enabling full for-comprehension support)- A typeclass instance for Cats’
Monad.
Americium’s implementation is stack-safe.
Running Tests
Instead of Prop.forAll
In Americium, you call .supplyTo on your Trials instance. You must specify a limit first:
trials.withLimit(100).supplyTo { caseValue =>
// Your assertion here
}
Multiple Parameters
Instead of taking multiple arguments in forAll, you gang trials together using .and:
(trials1 and trials2 and trials3)
.withLimit(100)
.supplyTo { (a, b, c) =>
// ...
}
Test Configuration
Scalacheck Test.Parameters |
Americium equivalent |
|---|---|
withMinSuccessfulTests |
trials.withLimit(n) |
withMaxDiscardRatio |
trials.withStrategy(c => CasesLimitStrategy.counted(n, discardRatio)) |
withInitialSeed |
trials.withLimit(n).withSeed(seed) |
withMaxSize |
trials.withLimit(n).withComplexityLimit(maxSize) |
Sized Generation
Americium uses api.complexities instead of Gen.size.
api.complexities.flatMap { complexity =>
// Build a trials instance based on the current complexity budget
}
This is often used with alternateWithWeights to create Complexity Budgeting (see Advanced Techniques).
Custom Shrink Instances
Delete them!
You no longer need to maintain separate shrink logic. If your Trials is built correctly using map, flatMap, and alternate, Americium will find the minimal case automatically.
Auto-Derivation
Americium uses the Magnolia library for auto-derivation via the Factory[T] typeclass.
import com.sageserpent.americium.Factory
// Deriving a Trials instance for a case class hierarchy
val rootTrials = implicitly[Factory[Root]].trials
For recursive structures in Scala 3, you may need an explicit given:
given evidence: Factory[Root] = Factory.autoDerived
Summary
Gen→Trials.Arbitrary→Factory.- Integrated Shrinkage means no more
Shrink[T]instances. - Plural naming convention for API methods.
- Explicit limits required before running (
.withLimit(n)).