Reviewed-on: #4
3.6 KiB
gs-datagen
GS Open Source | License (MIT)
Test data generation library for Scala 3. gs-datagen
provides composable
generator definitions that can be reused across tests.
Usage
Dependency
object Gs {
val Datagen: ModuleID =
"gs" %% "gs-datagen-core-v0" % "$VERSION"
}
Imports
The standard way to use gs-datagen
is to import the entire package, which
pulls in Gen[A]
, Generated[A]
and Datagen[A, -I]
:
import gs.datagen.v0._
Examples
For the following examples, the following types (abbreviated) are relevant:
opaque type Name = String
opaque type DateOfBirth = LocalDate
opaque type Karma = Long
enum Role:
case Regular, Mod, Admin
case class User(
name: Name,
dateOfBirth: DateOfBirth,
karma: Karma,
role: Role
)
Example: Generate a Random User
One way to go about this is to define generators for each type and then compose
those generators for User
:
import gs.datagen.v0._
import gs.datagen.v0.generators.MinMax
val nameGen: Gen[Name] =
Gen.string.alpha(4, 16).map(Name(_))
val dateOfBirthGen: Gen[LocalDate] =
Gen.date.beforeToday(
days = MinMax.Zero,
months = MinMax.nonNegative(0, 11),
years = MinMax.nonNegative(18, 80)
).map(DateOfBirth(_))
val karmaGen: Gen[Karma] =
Gen.long.inRange(-100L, 100L).map(Karma(_))
val roleGen: Gen[Role] =
Gen.oneOf.fixedChoices(Role.Regular, Role.Mod, Role.Admin)
and the composition:
val userGen: Gen[User] =
for
name <- nameGen
dateOfBirth <- dateOfBirthGen
karma <- karmaGen
role <- roleGen
yield User(name, dateOfBirth, karma, role)
Generators may also be defined inline if separate definitions are not useful:
val userGen: Gen[User] =
for
name <- Gen.string.alpha(4, 16).map(Name(_))
dateOfBirth <- dateOfBirthGen
karma <- Gen.long.inRange(-100L, 100L).map(Karma(_))
role <- roleGen
yield User(name, dateOfBirth, karma, role)
Once that generator exists, users may be generated:
val user: User = userGen.gen()
The Generated
type class can be used as well:
given Generated[User] = Generated.of(userGen)
val user2: User = Generated[User].generate()
Example: Require Input
What if we want a way to generate users randomly, but always require the caller to specify a user role? This can be accomplished by requiring input when generating data:
val roleUserGen: Datagen[User, Role] =
for
name <- Gen.string.alpha(4, 16).map(Name(_))
dateOfBirth <- dateOfBirthGen
karma <- Gen.long.inRange(-100L, 100L).map(Karma(_))
yield (role: Role) => User(name, dateOfBirth, karma, role)
The usage of this type is different and does not support Generated
:
val admin: User = roleUserGen.generate(Role.Admin)
val mod: User = roleUserGen.generate(Role.Mod)
val regular: User = roleUserGen.generate(Role.Regular)
Supported Generators
For a complete list of generators supported out of the box, please refer to the Gen definition, which enumerates and documents all options.
Donate
Enjoy this project or want to help me achieve my goals? Consider Donating to Pat on Ko-fi.