Arrived from Scalacheck?
Come on in and take the weight off your feet, we're friendly here. Like a nice refreshing glass of integrated shrinkage cordial?
If you want to speak Americium it's expected that you'll do so with a Scalacheck accent - here's a guide to translation:
First off, there is no Arbitrary
analogue. Gen[+T]
becomes Trials[+T]
. Easy.
(Actually, there is something called Factory
specifically for auto-derivation; that is a bit like Arbitrary
. We'll get to that in a bit...)
This is nearly always explicit (we'll cover auto-derivation in a bit).
Instead of using the companion object Gen
, either import Trials.api
or use a method defined on the Trials[T]
instance itself...
-
Gen.choose
,Gen.chooseNum
,Gen.chooseChar
,Gen.chooseBigInt
etc becomes one ofapi.integers
,api.doubles
,api.characters
,api.bigInts
etc, using the overloads that take lower and upper bounds. -
Gen.double
becomesapi.doubles
, using the overload without any parameters. -
Gen.long
becomesapi.longs
, using the overload without any parameters. -
Gen.oneOf
becomes eitherapi.choose
orapi.alternate
, depending on whether you originally fed inT
orGen[T]
. -
Gen.const
becomesapi.only
-
Gen.delay
becomesapi.delay
-
Gen.frequency
becomesapi.chooseWithWeights
-
Gen.failed
becomesapi.impossible
-
Gen.sequence
becomesapi.sequences
-
Gen.option
becomes<trials instance>.options
-
Gen.either
becomes<trials instance>.or
-
Gen.stringOf
becomes<character trials instance>.several
(Callingseveral
on a character trials will build string trials by default.) -
Gen.stringOfN
becomes<character trials instance>.lotsOfSize
(CallinglotsOfSize
on a character trials will build string trials by default.) -
Gen.listOf
becomes<trials instance>.lists
-
Gen.listOfN
becomes<trials instance>.listsOfSize
-
Gen.containerOf
becomes<trials instance>.several
-
Gen.containerOfN
becomes<trials instance>.lotsOfSize
NOTE: the methods in TrialsApi
often have names in the plural - so Gen.double
becomes api.doubles
, Gen.sequence
becomes api.sequences
and so on.
Trials
is a monad too, with a stack-safe implementation. It has a typeclass instance for Cats' Monad
. So you can map
, flatMap
, filter
and mapFilter
till you drop. There is even withFilter
so you can enjoy the full-fat for-comprehension flavour.
Throw away Prop.forAll
and call <trials instance>.withLimit(<limit>).supplyTo
instead.
If you have several Gen
instances, then gang together the corresponding trials with .and
:
(<trials one> and <trials two> and <trials three>).withLimit(<limit>).supplyTo
.
Substitute for Test.Parameters.withMinSuccessfulTests
and Test.Parameters.withMaxDiscardRatio
with <trials instance>.withStrategy(_ => CasesLimitStrategy.counted(<maximumNumberOfCases>, <maximumStarvationRatio>))
.
Substitute for Test.Parameters.withInitialSeed
with <supply-to syntax>.withSeed
, where <supplyToSyntax>
is <trials instance>.withLimit(<limit>)
etc.
Substitute for Test.Parameters.withMaxSize
with <supply-to syntax>.withComplexityLimit
, where <supplyToSyntax>
is <trials instance>.withLimit(<limit>)
etc.
Substitute Gen.size
with api.complexities
. This will reveal the appropriate complexity to your own code that builds up trials. Typically this is done in a flat-map: api.complexities.flatMap(complexity => <trials expression using the complexity>)
.
Delete them and dance a jig!
Your auto-derivation needs are met by com.sageserpent.americium.Factory
, which uses the marvellous Magnolia library under the hood.
If you have a case class hierarchy rooted at Root
and you want Trials<Root>
, then pull in an implicitly derived instance via:
Scala 2.13
implicitly[Factory[Root]].trials
Scala 3
given evidence: Factory[Root] = Factory.autoDerived // May need this if `Root` has a recursive definition like, say, `List[T]`.
implicitly[Factory[Root]].trials
As with Scalacheck-Shapeless, you will probably need to supply a few of your own implicit definitions to bootstrap the auto-derivation, it's the same drill only this time it is evidences for various Factory[T]
instantiations that you need to supply.
As a guide, here are the built-in implicit definitions for Scala 2.13 and Scala 3.
Next topic: JUnit5 again...
Start here: Project README
Topics:
-
Introducing Americium to your tests
Trials, supplying test cases to tests, shrinkage in action
-
Variations in making a trials instance
Choices, alternation, special cases
-
Collections, mapping, filtering, flat-mapping and recursion
-
Supplying independently varying test cases to a trial
-
Reproducing a failing test case quickly
Recipes and recipe hashes
-
What it means and how it is achieved
-
Configuration buttons, dials and levers
Case limit strategies, seeding, complexity, controlling shrinking
-
Sometimes the test doesn't even want to run itself
-
Going with the flow
-
Impress your friends with sleights of hand
-
Oh, that bunch?
-
Welcome to Americium - learn the local language
-
Strongly typed test supply
-
Yes, do pay attention to the man behind the curtain